[
  {
    "path": ".editorconfig",
    "content": "# https://editorconfig.org\nroot = true\n\n[*]\ncharset = utf-8\nindent_size = 4\nindent_style = space\ninsert_final_newline = true\nmax_line_length = 180\ntab_width = 4\ntrim_trailing_whitespace = true\nij_continuation_indent_size = 8\nij_formatter_off_tag = @formatter:off\nij_formatter_on_tag = @formatter:on\nij_formatter_tags_enabled = true\nij_smart_tabs = false\nij_visual_guides = 80,120,180\nij_wrap_on_typing = false\n\n[{*.yaml,*.yml}]\nindent_size = 2\n\n[{*.kt,*.kts}]\nij_kotlin_align_in_columns_case_branch = false\nij_kotlin_align_multiline_binary_operation = false\nij_kotlin_align_multiline_extends_list = false\nij_kotlin_align_multiline_method_parentheses = false\nij_kotlin_align_multiline_parameters = true\nij_kotlin_align_multiline_parameters_in_calls = false\nij_kotlin_allow_trailing_comma = false\nij_kotlin_allow_trailing_comma_on_call_site = false\nij_kotlin_assignment_wrap = normal\nij_kotlin_blank_lines_after_class_header = 0\nij_kotlin_blank_lines_around_block_when_branches = 0\nij_kotlin_blank_lines_before_declaration_with_comment_or_annotation_on_separate_line = 1\nij_kotlin_block_comment_add_space = false\nij_kotlin_block_comment_at_first_column = true\nij_kotlin_call_parameters_new_line_after_left_paren = true\nij_kotlin_call_parameters_right_paren_on_new_line = true\nij_kotlin_call_parameters_wrap = on_every_item\nij_kotlin_catch_on_new_line = false\nij_kotlin_class_annotation_wrap = split_into_lines\nij_kotlin_code_style_defaults = KOTLIN_OFFICIAL\nij_kotlin_continuation_indent_for_chained_calls = false\nij_kotlin_continuation_indent_for_expression_bodies = false\nij_kotlin_continuation_indent_in_argument_lists = false\nij_kotlin_continuation_indent_in_elvis = false\nij_kotlin_continuation_indent_in_if_conditions = false\nij_kotlin_continuation_indent_in_parameter_lists = false\nij_kotlin_continuation_indent_in_supertype_lists = false\nij_kotlin_else_on_new_line = false\nij_kotlin_enum_constants_wrap = off\nij_kotlin_extends_list_wrap = normal\nij_kotlin_field_annotation_wrap = split_into_lines\nij_kotlin_finally_on_new_line = false\nij_kotlin_if_rparen_on_new_line = true\nij_kotlin_import_nested_classes = false\nij_kotlin_imports_layout = android.**,androidx.**,com.android.**,com.saveourtool.diktat.**,*,java.**,javax.**,kotlin.**,kotlinx.**,^\nij_kotlin_insert_whitespaces_in_simple_one_line_method = true\nij_kotlin_keep_blank_lines_before_right_brace = 2\nij_kotlin_keep_blank_lines_in_code = 2\nij_kotlin_keep_blank_lines_in_declarations = 2\nij_kotlin_keep_first_column_comment = true\nij_kotlin_keep_indents_on_empty_lines = false\nij_kotlin_keep_line_breaks = true\nij_kotlin_lbrace_on_next_line = false\nij_kotlin_line_comment_add_space = false\nij_kotlin_line_comment_add_space_on_reformat = false\nij_kotlin_line_comment_at_first_column = true\nij_kotlin_method_annotation_wrap = split_into_lines\nij_kotlin_method_call_chain_wrap = normal\nij_kotlin_method_parameters_new_line_after_left_paren = true\nij_kotlin_method_parameters_right_paren_on_new_line = true\nij_kotlin_method_parameters_wrap = on_every_item\nij_kotlin_name_count_to_use_star_import = 2147483647\nij_kotlin_name_count_to_use_star_import_for_members = 2147483647\nij_kotlin_parameter_annotation_wrap = off\nij_kotlin_space_after_comma = true\nij_kotlin_space_after_extend_colon = true\nij_kotlin_space_after_type_colon = true\nij_kotlin_space_before_catch_parentheses = true\nij_kotlin_space_before_comma = false\nij_kotlin_space_before_extend_colon = true\nij_kotlin_space_before_for_parentheses = true\nij_kotlin_space_before_if_parentheses = true\nij_kotlin_space_before_lambda_arrow = true\nij_kotlin_space_before_type_colon = false\nij_kotlin_space_before_when_parentheses = true\nij_kotlin_space_before_while_parentheses = true\nij_kotlin_spaces_around_additive_operators = true\nij_kotlin_spaces_around_assignment_operators = true\nij_kotlin_spaces_around_equality_operators = true\nij_kotlin_spaces_around_function_type_arrow = true\nij_kotlin_spaces_around_logical_operators = true\nij_kotlin_spaces_around_multiplicative_operators = true\nij_kotlin_spaces_around_range = false\nij_kotlin_spaces_around_relational_operators = true\nij_kotlin_spaces_around_unary_operator = false\nij_kotlin_spaces_around_when_arrow = true\nij_kotlin_variable_annotation_wrap = off\nij_kotlin_while_on_new_line = false\nij_kotlin_wrap_elvis_expressions = 1\nij_kotlin_wrap_expression_body_functions = 1\nij_kotlin_wrap_first_method_in_call_chain = false\n\n# disable ktlint rules\nktlint_standard = disabled\nktlint_experimental = disabled\nktlint_test = disabled\nktlint_custom = disabled\n"
  },
  {
    "path": ".git-hooks/commit-msg.sh",
    "content": "#!/usr/bin/env bash\n\ncommit_pattern=\"(Merge (remote-tracking )?branch|### What's done:)\"\nerror_msg=\"Your commit message doesn't match the pattern $commit_pattern. Please fix it.\"\ncommit_count=\"$(git rev-list --count master..HEAD 2> /dev/null)\"\n\nif [[ $commit_count = \"0\" && ! $( cat \"$1\" ) =~ $commit_pattern ]]\nthen\n    echo \"$error_msg\"\n    exit 1\nfi\n\nexit 0\n"
  },
  {
    "path": ".git-hooks/pre-commit.sh",
    "content": "#!/usr/bin/env bash\n\nbranch_name=\"$(git rev-parse --abbrev-ref HEAD)\"\nbranch_pattern=\"^(feature|bugfix|hotfix|infra)/.*$\"\nerror_message=\"Your branch name doesn't match the pattern $branch_pattern. Please correct it before committing.\"\n\nif [[ ! $branch_name =~ $branch_pattern ]]\nthen\n  echo \"$error_message\"\n  exit 1\nfi\n\nexit 0\n"
  },
  {
    "path": ".gitattributes",
    "content": "* text=auto\n*.bat eol=crlf\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/bug_report.md",
    "content": "---\nname: Bug report\nabout: Create a report to help us improve\ntitle: ''\nlabels: 'bug'\n\n---\n\n## Describe the bug\n\n## Expected behavior\n\n## Observed behavior\n\n## Steps to Reproduce\n\n## Environment information\n* diktat version:\n* build tool (maven/gradle):\n* how is diktat run (CLI, plugin, etc.):\n* kotlin version:\n* operating system:\n* link to a project (if your project is public):\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/config.yml",
    "content": "blank_issues_enabled: true\ncontact_links:\n  - name: Discussions\n    url: https://github.com/saveourtool/diktat/discussions\n    about: Ask everything about diktat in discussions tab\n"
  },
  {
    "path": ".github/codecov.yml",
    "content": "codecov:\n  max_report_age: off\ncoverage:\n  status:\n    project:\n      default:\n        threshold: 2%"
  },
  {
    "path": ".github/pull_request_template.md",
    "content": "## Which rule and warnings did you add?\n\nThis pull request closes <!-- insert related issue number -->\n<!-- Briefly describe rule and warnings -->\n\n## Actions checklist\n* [ ] Implemented Rule, added Warnings\n* [ ] Added tests on checks\n* [ ] Added tests on fixers\n* [ ] Updated diktat-analysis.yml\n* [ ] Updated available-rules.md\n\n## Fixme\n\n<!-- Is there anything left out of scope of this PR? -->\n"
  },
  {
    "path": ".github/workflows/build_and_test.yml",
    "content": "# vim:ai et ts=2 sts=2 sw=2:\nname: Build and test\n\non:\n  pull_request:\n  push:\n    branches:\n      - 'master'\n\nconcurrency:\n    # https://docs.github.com/en/actions/using-jobs/using-concurrency\n    # The latest queued workflow is preferred; the ones already in progress get cancelled\n    # Workflows on master branch shouldn't be cancelled, that's why they are identified by commit SHA\n    group: ${{ github.ref == 'refs/heads/master' && format('{0}-{1}', github.workflow, github.sha) || format('{0}-{1}', github.workflow, github.ref) }}\n    cancel-in-progress: true\n\nenv:\n  GRADLE_OPTS: -Dorg.gradle.daemon=true -Dorg.gradle.parallel=true -Dorg.gradle.welcome=never\n  GPG_SEC: ${{ secrets.PGP_SEC }}\n  GPG_PASSWORD: ${{ secrets.PGP_PASSWORD }}\n  OSSRH_USERNAME: ${{ secrets.SONATYPE_USER }}\n  OSSRH_PASSWORD: ${{ secrets.SONATYPE_PASSWORD }}\n  GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n\njobs:\n  build_and_test_with_code_coverage:\n    name: Build, test and upload code coverage\n    runs-on: ubuntu-latest\n\n    steps:\n      - uses: actions/checkout@v4\n        with:\n            # required for correct codecov upload\n            fetch-depth: 0\n      - name: Set up JDK 11\n        uses: actions/setup-java@v4\n        with:\n          java-version: 11\n          distribution: temurin\n      - name: Retrieve Kotlin version\n        run: |\n          kv=$(cat gradle/libs.versions.toml | grep '^kotlin =' | awk -F'[=]' '{print $2}' | tr -d '\" ')\n          echo KOTLIN_VERSION=$kv >> $GITHUB_ENV\n        shell: bash\n      - name: Cache konan\n        uses: actions/cache@v4\n        with:\n          path: ~/.konan\n          key: ${{ runner.os }}-gradle-konan-${{ env.KOTLIN_VERSION }}\n      - name: Build all\n        uses: gradle/gradle-build-action@v3\n        with:\n          gradle-version: wrapper\n          gradle-home-cache-cleanup: true\n          arguments: |\n            build\n            -x detekt\n            --scan\n            --build-cache\n\n      - name: Upload gradle reports\n        if: ${{ always() }}\n        uses: actions/upload-artifact@v4\n        with:\n          name: gradle-reports\n          path: '**/build/reports/'\n          retention-days: 1\n      - name: Code coverage report\n        uses: codecov/codecov-action@v5\n        # Do not run coverage for forks since they cannot upload the results to codecov.\n        # For reference, see:\n        # https://docs.github.com/en/actions/using-jobs/using-conditions-to-control-job-execution#example-only-run-job-for-specific-repository\n        if: github.repository == 'saveourtool/diktat'\n        with:\n          fail_ci_if_error: false\n          token: ${{ secrets.CODECOV_TOKEN }}\n\n  build_and_test:\n    name: Build and test\n    runs-on: ${{ matrix.os }}\n    strategy:\n      # We need multiple builds to run even if the 1st one is failing, because\n      # test failures may be OS-specific (or the tests themselves flaky).\n      fail-fast: false\n      matrix:\n        os: [ ubuntu-latest, windows-latest, macos-latest ]\n\n    # A possible workaround for <https://github.com/dorny/test-reporter/issues/168>.\n    permissions:\n      checks: write\n      contents: write\n      pull-requests: write\n      statuses: write\n      packages: write\n\n    steps:\n      - uses: actions/checkout@v4\n      - name: Set up JDK 11\n        uses: actions/setup-java@v4\n        with:\n          java-version: 11\n          distribution: temurin\n      - name: Retrieve Kotlin version\n        run: |\n          kv=$(cat gradle/libs.versions.toml | grep '^kotlin =' | awk -F'[=]' '{print $2}' | tr -d '\" ')\n          echo KOTLIN_VERSION=$kv >> $GITHUB_ENV\n        shell: bash\n      - name: Cache konan\n        uses: actions/cache@v4\n        with:\n          path: ~/.konan\n          key: ${{ runner.os }}-gradle-konan-${{ env.KOTLIN_VERSION }}\n\n      - name: Build all\n        uses: gradle/gradle-build-action@v3\n        with:\n          gradle-version: wrapper\n          gradle-home-cache-cleanup: true\n          arguments: |\n            build\n            -x detekt\n            --scan\n            --build-cache\n\n        # This step needs a Git repository, so it's impossible to extract it\n        # into a separate job (or, otherwise, we'd need to upload the content\n        # of the whole `.git` folder as an artifact).\n      - name: JUnit Tests (dorny/test-reporter@v1)\n        uses: dorny/test-reporter@v1\n        if: ${{ always() }}\n        with:\n          name: JUnit Tests (${{ runner.os }}, dorny/test-reporter@v1)\n          # Comma-separated values.\n          path: \"**/build/test-results/*/TEST-*.xml\"\n          reporter: java-junit\n        # Ignore the \"Resource not accessible by integration\" error when a PR\n        # originates from a non-collaborator. This is\n        # <https://github.com/dorny/test-reporter/issues/168> which may be\n        # potentially fixed with <https://github.com/dorny/test-reporter/pull/174>.\n        continue-on-error: true\n\n      - name: Upload test results\n        uses: actions/upload-artifact@v4\n        if: ${{ always() }}\n        with:\n          name: xml-test-reports-${{ runner.os }}\n          path: |\n            **/build/test-results/*/TEST-*.xml\n          retention-days: 1\n\n      - name: Upload gradle reports\n        if: ${{ always() }}\n        uses: actions/upload-artifact@v4\n        with:\n          name: gradle-test-report-${{ matrix.os }}\n          path: '**/build/reports/'\n          retention-days: 1\n\n      - name: 'Publish a snapshot to GitHub'\n        id: publish-github\n        if: ${{ github.event_name == 'push' && github.ref_type == 'branch' && github.ref == 'refs/heads/master' && github.repository == 'saveourtool/diktat' }}\n        uses: gradle/gradle-build-action@v3\n        with:\n          gradle-version: wrapper\n          arguments: |\n            -Preckon.stage=snapshot\n            publishAllPublicationsToGitHubRepository\n\n      - name: 'Publish a snapshot to Maven Central'\n        id: publish-sonatype\n        if: ${{ github.event_name == 'push' && github.ref_type == 'branch' && github.ref == 'refs/heads/master' && github.repository == 'saveourtool/diktat' }}\n        uses: gradle/gradle-build-action@v3\n        with:\n          gradle-version: wrapper\n          arguments: |\n            -Preckon.stage=snapshot\n            publishToSonatype\n            closeAndReleaseSonatypeStagingRepository\n\n  report:\n    name: Publish JUnit test results\n    if: ${{ always() }}\n    needs: build_and_test\n    runs-on: ${{ matrix.os }}\n\n    strategy:\n      matrix:\n        os: [ windows-latest, macos-latest ]\n\n    permissions:\n      checks: write\n      pull-requests: write\n\n    steps:\n      - uses: actions/download-artifact@v4\n        if: ${{ always() }}\n        with:\n          name: xml-test-reports-${{ runner.os }}\n\n        # Uses Docker, that's why Linux-only.\n      - name: JUnit Tests (EnricoMi/publish-unit-test-result-action@v2, Linux)\n        uses: EnricoMi/publish-unit-test-result-action@v2\n        if: ${{ runner.os == 'Linux' }}\n        with:\n          check_name: JUnit Tests (${{ runner.os }}, EnricoMi/publish-unit-test-result-action@v2)\n          junit_files: |\n            **/build/test-results/*/TEST-*.xml\n\n      - name: JUnit Tests (EnricoMi/publish-unit-test-result-action@v2, Windows or Mac OS X)\n        uses: EnricoMi/publish-unit-test-result-action/composite@v2\n        if: ${{ runner.os == 'Windows' || runner.os == 'macOS' }}\n        with:\n          check_name: JUnit Tests (${{ runner.os }}, EnricoMi/publish-unit-test-result-action@v2)\n          junit_files: |\n            **/build/test-results/*/TEST-*.xml\n"
  },
  {
    "path": ".github/workflows/codeql-analysis.yml",
    "content": "# For most projects, this workflow file will not need changing; you simply need\n# to commit it to your repository.\n#\n# You may wish to alter this file to override the set of languages analyzed,\n# or to provide custom queries or build logic.\nname: \"CodeQL\"\n\non:\n  push:\n    branches: [master]\n  pull_request:\n    # The branches below must be a subset of the branches above\n    branches: [master]\n  schedule:\n    - cron: '0 20 * * 5'\n\njobs:\n  analyze:\n    name: Analyze\n    runs-on: ubuntu-latest\n\n    strategy:\n      fail-fast: false\n      matrix:\n        # Override automatic language detection by changing the below list\n        # Supported options are ['csharp', 'cpp', 'go', 'java', 'javascript', 'python']\n        language: ['kotlin']\n        # Learn more...\n        # https://docs.github.com/en/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#overriding-automatic-language-detection\n\n    steps:\n    - name: Checkout repository\n      uses: actions/checkout@v4\n      with:\n        # We must fetch at least the immediate parents so that if this is\n        # a pull request then we can checkout the head.\n        fetch-depth: 2\n\n    # Initializes the CodeQL tools for scanning.\n    - name: Initialize CodeQL\n      uses: github/codeql-action/init@v3\n      with:\n        languages: ${{ matrix.language }}\n        # If you wish to specify custom queries, you can do so here or in a config file.\n        # By default, queries listed here will override any specified in a config file.\n        # Prefix the list here with \"+\" to use these queries and those in the config file.\n        # queries: ./path/to/local/query, your-org/your-repo/queries@main\n\n    # Autobuild attempts to build any compiled languages  (C/C++, C#, or Java).\n    # If this step fails, then you should remove it and run the build manually (see below)\n    # - name: Autobuild\n    #   uses: github/codeql-action/autobuild@v2\n\n    # ℹ️ Command-line programs to run using the OS shell.\n    # 📚 https://git.io/JvXDl\n\n    # ✏️ If the Autobuild fails above, remove it and uncomment the following three lines\n    #    and modify them (or add more) to build your code if your project\n    #    uses a compiled language\n\n    - uses: gradle/gradle-build-action@v3\n      with:\n        gradle-version: wrapper\n        # The `--continue` flag is necessary so that Gradle keeps going after the 1st test failure.\n        # By default, when test for all MPP targets are executed, Kotlin Gradle Plugin generates a single aggregated HTML report.\n        # Property `kotlin.tests.individualTaskReports` enables individual Junit-style XML reports.\n        # See org.jetbrains.kotlin.gradle.testing.internal.KotlinTestReport.\n        arguments: |\n          build\n          --continue\n          -x detekt\n          -Pkotlin.tests.individualTaskReports=true\n          -Porg.gradle.caching=true\n          -Pdetekt.multiplatform.disabled=true\n          -PdisableRedundantTargets=true\n          -PenabledExecutables=debug\n          -PgprUser=${{ github.actor }}\n          -PgprKey=${{ secrets.GITHUB_TOKEN }}\n\n    - name: Perform CodeQL Analysis\n      uses: github/codeql-action/analyze@v3\n"
  },
  {
    "path": ".github/workflows/dependencies.yml",
    "content": "name: 'Dependencies'\n\non:\n  push:\n    branches:\n      - 'master'\n\nenv:\n  GRADLE_OPTS: -Dorg.gradle.daemon=true -Dorg.gradle.parallel=true -Dorg.gradle.welcome=never\n\njobs:\n  dependencies:\n    name: 'Dependencies'\n    runs-on: ubuntu-latest\n\n    # The Dependency Submission API requires write permission.\n    permissions:\n      contents: write\n\n    steps:\n      - uses: actions/checkout@v4\n        with:\n          # Fetch Git tags, so that semantic version can be calculated.\n          # Alternatively, run `git fetch --prune --unshallow --tags` as the\n          # next step, see\n          # https://github.com/actions/checkout/issues/206#issuecomment-607496604.\n          fetch-depth: 0\n\n      - name: 'Set up Java 11'\n        uses: actions/setup-java@v4\n        with:\n          distribution: 'zulu'\n          java-version: 11\n\n      - name: 'Run snapshot action'\n        uses: mikepenz/gradle-dependency-submission@v1.0.0\n        with:\n          use-gradlew: true\n          gradle-build-module: |-\n            :diktat-api\n            :diktat-common-test\n            :diktat-ktlint-engine\n            :diktat-gradle-plugin\n            :diktat-maven-plugin\n            :diktat-rules\n            :diktat-ruleset\n            :diktat-runner\n            :diktat-dev-ksp\n            :diktat-cli\n          gradle-build-configuration: |-\n            compileClasspath\n          sub-module-mode: 'INDIVIDUAL'\n"
  },
  {
    "path": ".github/workflows/detekt.yml",
    "content": "name: Run deteKT\n\non:\n  push:\n    branches: [ master ]\n  pull_request:\n\njobs:\n  detekt_check:\n    runs-on: ubuntu-latest\n    permissions:\n      # required for all workflows\n      security-events: write\n\n    steps:\n      - uses: actions/checkout@v4\n      - name: Set up JDK 11\n        uses: actions/setup-java@v4\n        with:\n          java-version: 11\n          distribution: temurin\n      - uses: gradle/gradle-build-action@v3\n        with:\n          gradle-version: wrapper\n          arguments: |\n            detektAll\n            --build-cache\n            --continue\n            -PgprUser=${{ github.actor }}\n            -PgprKey=${{ secrets.GITHUB_TOKEN }}\n      - name: Upload SARIF report to Github\n        uses: github/codeql-action/upload-sarif@v3\n        if: ${{ always() }}\n        with:\n          sarif_file: build/detekt-sarif-reports/detekt-merged.sarif\n      - name: Upload SARIF artifacts\n        uses: actions/upload-artifact@v4\n        if: ${{ failure() }}\n        with:\n          name: sarif-reports\n          path: \"**/build/detekt-sarif-reports/\"\n          retention-days: 1\n"
  },
  {
    "path": ".github/workflows/diktat.yml",
    "content": "name: Run diKTat (release)\n\non:\n  push:\n    branches: [ master ]\n  pull_request:\n    branches: [ master ]\n\njobs:\n  diktat_check:\n    runs-on: ubuntu-latest\n    permissions:\n      # required for all workflows\n      security-events: write\n\n    steps:\n      - uses: actions/checkout@v4\n\n      - name: Set up JDK 11\n        uses: actions/setup-java@v4\n        with:\n          java-version: 11\n          distribution: temurin\n\n      - uses: gradle/gradle-build-action@v3\n        with:\n          gradle-version: wrapper\n          arguments: |\n            diktatCheck\n            mergeDiktatReports\n            -Pdiktat.githubActions=true\n            -Pdetekt.multiplatform.disabled=true\n            --continue\n            --build-cache\n            -PgprUser=${{ github.actor }}\n            -PgprKey=${{ secrets.GITHUB_TOKEN }}\n            --stacktrace\n      - name: Upload SARIF report to Github\n        uses: github/codeql-action/upload-sarif@v3\n        if: ${{ always() }}\n        with:\n          sarif_file: build/reports/diktat/diktat-merged.sarif\n      - name: Upload SARIF artifacts\n        uses: actions/upload-artifact@v4\n        if: ${{ failure() }}\n        with:\n          name: sarif-reports\n          path: \"**/build/reports/diktat\"\n          retention-days: 1\n"
  },
  {
    "path": ".github/workflows/diktat_snapshot.yml",
    "content": "name: Run diKTat (snapshot)\n\non:\n  push:\n    branches: [ master ]\n  pull_request:\n    branches: [ master ]\n\njobs:\n  diktat_snapshot_check:\n    name: 'Check the project using diktat snapshot plugin'\n    runs-on: ubuntu-latest\n    permissions:\n      # required for all workflows\n      security-events: write\n\n    steps:\n      - uses: actions/checkout@v4\n        with:\n          # Fetch Git tags, so that semantic version can be calculated.\n          # Alternatively, run `git fetch --prune --unshallow --tags` as the\n          # next step, see\n          # https://github.com/actions/checkout/issues/206#issuecomment-607496604.\n          fetch-depth: 0\n\n      - name: Set up JDK 11\n        uses: actions/setup-java@v4\n        with:\n          java-version: 11\n          distribution: temurin\n\n      - name: 'Cache ~/.konan'\n        id: cache-konan\n        uses: actions/cache@v4\n        with:\n          path: |\n            ~/.konan\n          key: ${{ runner.os }}-konan-${{ hashFiles('**/*.gradle.kts', '**/gradle-wrapper.properties') }}-build-java${{ matrix.java-version }}\n          restore-keys: |\n            ${{ runner.os }}-konan-${{ hashFiles('**/*.gradle.kts', '**/gradle-wrapper.properties') }}-\n            ${{ runner.os }}-konan-\n\n      - name: 'Publish a snapshot version to local repo'\n        id: generateLibsForDiktatSnapshot\n        uses: gradle/gradle-build-action@v3\n        with:\n          gradle-version: wrapper\n          arguments: |\n            :generateLibsForDiktatSnapshot\n            -x detekt\n            -x test\n            -x diktatCheck\n\n      # copied from .github/workflows/diktat.yml\n      - uses: gradle/gradle-build-action@v3\n        with:\n          gradle-version: wrapper\n          arguments: |\n            diktatCheck\n            mergeDiktatReports\n            -Pdiktat.githubActions=true\n            -Pdetekt.multiplatform.disabled=true\n            --continue\n            --build-cache\n            -PgprUser=${{ github.actor }}\n            -PgprKey=${{ secrets.GITHUB_TOKEN }}\n      - name: Upload SARIF report to Github\n        uses: github/codeql-action/upload-sarif@v3\n        if: ${{ always() }}\n        with:\n          sarif_file: build/reports/diktat/diktat-merged.sarif\n          # override category to have a different with release version\n          category: diktat (snapshot)\n      - name: Upload SARIF artifacts\n        uses: actions/upload-artifact@v4\n        if: ${{ failure() }}\n        with:\n          name: sarif-reports\n          path: \"**/build/reports/diktat\"\n          retention-days: 1\n"
  },
  {
    "path": ".github/workflows/release.yml",
    "content": "name: Create diKTat release\n\non:\n  push:\n    tags:\n      - 'v*'\n\nenv:\n  GRADLE_OPTS: -Dorg.gradle.daemon=true -Dorg.gradle.parallel=true -Dorg.gradle.welcome=never\n  GPG_SEC: ${{ secrets.PGP_SEC }}\n  GPG_PASSWORD: ${{ secrets.PGP_PASSWORD }}\n  OSSRH_USERNAME: ${{ secrets.SONATYPE_USER }}\n  OSSRH_PASSWORD: ${{ secrets.SONATYPE_PASSWORD }}\n  GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n\njobs:\n  release:\n    name: 'Release'\n    runs-on: ubuntu-latest\n\n    steps:\n      - uses: actions/checkout@v4\n        with:\n          # Fetch Git tags, so that semantic version can be calculated.\n          # Alternatively, run `git fetch --prune --unshallow --tags` as the\n          # next step, see\n          # https://github.com/actions/checkout/issues/206#issuecomment-607496604.\n          fetch-depth: 0\n\n      - name: 'Set up Java'\n        uses: actions/setup-java@v4\n        with:\n          java-version: 11\n          distribution: temurin\n\n      - name: 'Calculate the release version'\n        run: |\n          echo \"RELEASE_VERSION=${GITHUB_REF#'refs/tags/v'}\" >> $GITHUB_ENV\n\n      - name: 'Publish a release to Maven Central'\n        id: publish-sonatype\n        uses: gradle/gradle-build-action@v3\n        with:\n          gradle-version: wrapper\n          arguments: |\n            publishToSonatype\n            closeAndReleaseSonatypeStagingRepository\n\n      - name: 'Publish a release to Gradle Plugins'\n        id: publish-gradle\n        uses: gradle/gradle-build-action@v3\n        with:\n          gradle-version: wrapper\n          arguments: |\n            :diktat-gradle-plugin:publishPlugins\n            -Pgradle.publish.key=${{ secrets.GRADLE_KEY }}\n            -Pgradle.publish.secret=${{ secrets.GRADLE_SECRET }}\n\n      - name: 'Publish a release to GitHub'\n        id: publish-github\n        uses: gradle/gradle-build-action@v3\n        with:\n          gradle-version: wrapper\n          arguments: |\n            shadowExecutableJar\n            publishAllPublicationsToGitHubRepository\n      - name: 'GitHub Release'\n        id: create_release\n        uses: actions/create-release@v1\n        with:\n          tag_name: ${{ github.ref }}\n          release_name: Release ${{ env.RELEASE_VERSION }}\n          draft: false\n          prerelease: false\n      - name: Upload Diktat CLI to GitHub release\n        id: upload-release-asset-cli\n        uses: actions/upload-release-asset@v1\n        env:\n          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n        with:\n          upload_url: ${{ steps.create_release.outputs.upload_url }}\n          asset_path: ./diktat-cli/build/diktat-cli-${{ env.RELEASE_VERSION }}\n          asset_name: diktat\n          asset_content_type: application/zip\n      - name: Upload Diktat CLI for Windows to GitHub release\n        id: upload-release-asset-cli-win\n        uses: actions/upload-release-asset@v1\n        env:\n          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n        with:\n          upload_url: ${{ steps.create_release.outputs.upload_url }}\n          asset_path: ./diktat-cli/src/main/script/diktat.cmd\n          asset_name: diktat.cmd\n          asset_content_type: application/octet-stream\n      - name: Upload Diktat ruleset for KtLint to GitHub release\n        id: upload-release-asset-ruleset\n        uses: actions/upload-release-asset@v1\n        env:\n          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n        with:\n          upload_url: ${{ steps.create_release.outputs.upload_url }}\n          asset_path: ./diktat-ruleset/build/libs/diktat-${{ env.RELEASE_VERSION }}.jar\n          asset_name: diktat-${{ env.RELEASE_VERSION }}.jar\n          asset_content_type: application/zip\n"
  },
  {
    "path": ".gitignore",
    "content": "target/\n.gradle/\nbuild/\n!ktlint/src/main/resources/config/.idea\n.idea/\n*.iml\n/examples/*/gradlew\n/examples/*/gradlew.bat\n/examples/*/gradle/wrapper/\nout/\n.DS_Store\n\n# Vim swap files\n*.swp\n\n*.sarif\n\n# a generated file for github action\n/gradle/libs.versions.toml_backup\n"
  },
  {
    "path": "CNAME",
    "content": "diktat.saveourtool.com"
  },
  {
    "path": "CODE_OF_CONDUCT.md",
    "content": "# Code of Conduct\n\nThis is a small code of conduct to have a good and friendly development in diKTat\n\n## Good behavior\n\nWe expect everyone to love each other, be kind and polite.\nDo not hate anyone for comments on the review or for bugs that he (or she) made in his code.\n\n## Unacceptable behavior\n\nBut if you would like to bully some of our contributors - you are always welcome.\nWe love critics and do not like to be in comfort zone.\nWe can even organize some underground boxing match for you somewhere in Russia. "
  },
  {
    "path": "CONTRIBUTING.md",
    "content": "# Contributing\n\nIf you are reading this - then you have decided to contribute to our project. Oh, poor you...\nRules are very simple:\n1. Fork this repository to your own account\n2. Make your changes and verify that tests pass (or wait that our CI/CD will do everything for you)\n3. Commit your work and push to a new branch on your fork\n4. Submit a pull request\n5. Participate in the code review process by responding to feedback\n\n# Technical part\n\nMain components are:\n1) diktat-rules — number of rules that are supported by diKTat;\n2) diktat-common-test — util methods for functional/unit tests that can be used for running your code fixer on the initial code and compare it with the expected result;\n3) also see our demo: diktat-demo in a separate repository.\n\nMainly we wanted to create a common configurable mechanism that\nwill give us a chance to enable/disable and customize all rules.\nThat's why we added logic for:\n1) Parsing `.yml` file with configurations of rules and passing it to visitors;\n2) Passing information about properties to visitors.\n   This information is very useful, when you are trying to get,\n   for example, a filename of file where the code is stored;\n3) We added a bunch of visitors, checkers and fixers that will extended KTlint functionaliity with code style rules;\n4) We have proposed a code style for Kotlin language.\n\nBefore you make a pull request, make sure the build is clean as we have lot of tests and other prechecks:\n\n```bash\n$ mvn clean install\n```\n\n# Hooks\n\nWe have some hooks to a commit messages:\n1) your commit message should have the following format:\n```\nBrief Description\n\n### What's done:\n1) Long description\n2) Long description\n```\n\n2) Please also do not forget to update documentation on Wiki after the merge approval and before merge.\n"
  },
  {
    "path": "LICENSE",
    "content": "The MIT License\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in\nall copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\nTHE SOFTWARE.\n"
  },
  {
    "path": "README.md",
    "content": "<img src=\"/logo.svg\" width=\"64px\"/>\n\n![Build and test](https://github.com/saveourtool/diKTat/workflows/Build%20and%20test/badge.svg?branch=master)\n![deteKT static analysis](https://github.com/saveourtool/diKTat/workflows/Run%20deteKT/badge.svg)\n![diKTat code style](https://github.com/saveourtool/diKTat/workflows/Run%20diKTat%20%28release%29/badge.svg?branch=master)\n[![codecov](https://codecov.io/gh/saveourtool/diKTat/branch/master/graph/badge.svg)](https://codecov.io/gh/saveourtool/diKTat)\n\n[![Releases](https://img.shields.io/github/v/release/saveourtool/diKTat)](https://github.com/saveourtool/diKTat/releases)\n[![Maven Central](https://img.shields.io/maven-central/v/com.saveourtool.diktat/diktat-rules)](https://mvnrepository.com/artifact/com.saveourtool.diktat)\n[![FOSSA Status](https://app.fossa.com/api/projects/git%2Bgithub.com%2Fsaveourtool%2Fdiktat.svg?type=shield)](https://app.fossa.com/projects/git%2Bgithub.com%2Fsaveourtool%2Fdiktat?ref=badge_shield)\n[![Chat on Telegram](https://img.shields.io/badge/Chat%20on-Telegram-brightgreen.svg)](https://t.me/diktat_support)\n\n[![Hits-of-Code](https://hitsofcode.com/github/saveourtool/diktat)](https://hitsofcode.com/view/github/saveourtool/diktat)\n![Lines of code](https://img.shields.io/tokei/lines/github/saveourtool/diktat)\n![GitHub repo size](https://img.shields.io/github/repo-size/saveourtool/diktat)\n[![Awesome Kotlin Badge](https://kotlin.link/awesome-kotlin.svg)](https://github.com/KotlinBy/awesome-kotlin)\n\n\n**DiKTat** is a strict [coding standard](info/guide/diktat-coding-convention.md) for Kotlin, consisting of a collection of [Kotlin](https://kotlinlang.org/) code style rules implemented as Abstract Syntax Tree (AST) visitors built on top of [KTlint](https://ktlint.github.io/). It serves the purpose of detecting and automatically fixing code smells in the Continuous Integration/Continuous Deployment (CI/CD) process. You can find the comprehensive list of supported rules and inspections [here](info/available-rules.md).\n\nDiKTat has gained recognition and has been added to the lists of [static analysis tools](https://github.com/analysis-tools-dev/static-analysis), [kotlin-awesome](https://github.com/KotlinBy/awesome-kotlin), and [kompar](https://catalog.kompar.tools/Analyzer/diKTat/1.2.5). We extend our gratitude to the community for this support!\n\n## See first\n\n|  |  |  |  |  |  |\n| --- | --- | --- | --- | --- | --- |\n|[Codestyle](info/guide/diktat-coding-convention.md)|[Inspections](info/available-rules.md) | [Examples](examples) | [Demo](https://saveourtool.com/#/demo/diktat) | [White Paper](wp/wp.pdf) | [Groups of Inspections](info/rules-mapping.md) |\n\n## Why Choose DiKTat for CI/CD?\n\nWhile there are other tools like `detekt` and `ktlint` performing static analysis, you might wonder why DiKTat is necessary. Here are the key reasons:\n\n1. **More Inspections:** DiKTat boasts over 100 inspections tightly coupled with its [Codestyle](info/guide/diktat-coding-convention.md).\n\n2. **Unique Inspections:** DiKTat introduces unique inspections not found in other linters.\n\n3. **Highly Configurable:** Every inspection is highly configurable, allowing customization and suppression. Check [configuration options](#config) and [suppression](#suppress).\n\n4. **Strict Codestyle:** DiKTat enforces a detailed [Codestyle](info/guide/diktat-coding-convention.md) that can be adopted and applied in your project.\n\n## Run as [CLI-application](diktat-cli/README.md)\n\n### Download binary\n\n1. Download diKTat manually: [here](https://github.com/saveourtool/diktat/releases)\n\n   **OR** use `curl`:\n   ```shell\n   curl -sSLO https://github.com/saveourtool/diktat/releases/download/v2.0.0/diktat && chmod a+x diktat\n   ```\n\n_**For Windows only**_. Download diKTat.cmd manually: [here](https://github.com/saveourtool/diktat/releases)\n\n### Run diKTat\n\nFinally, run KTlint (with diKTat injected) to check your '*.kt' files in 'dir/your/dir':\n\n```console\n$ ./diktat \"dir/your/dir/**/*.kt\"\n```\n\n> _**On Windows**_\n> ```console\n> diktat.bat \"dir/your/dir/**/*.kt\"\n> ```\n\nTo **autofix** all code style violations, use `--mode fix` option.\n\n## Run with Maven using diktat-maven-plugin\n\nYou can see how it is configured in our examples:\n- [Single project](examples/maven/pom.xml)\n- [Multi-module project](examples/maven-multiproject/pom.xml)\n\n<details>\n<summary>Add this plugin to your pom.xml:</summary>\n\n```xml\n            <plugin>\n                <groupId>com.saveourtool.diktat</groupId>\n                <artifactId>diktat-maven-plugin</artifactId>\n                <version>${diktat.version}</version>\n                <executions>\n                    <execution>\n                        <id>diktat</id>\n                        <phase>none</phase>\n                        <goals>\n                            <goal>check</goal>\n                            <goal>fix</goal>\n                        </goals>\n                        <configuration>\n                            <inputs>\n                                <input>${project.basedir}/src/main/kotlin</input>\n                                <input>${project.basedir}/src/test/kotlin</input>\n                            </inputs>\n                            <diktatConfigFile>diktat-analysis.yml</diktatConfigFile>\n                           <excludes>\n                              <exclude>${project.basedir}/src/test/kotlin/excluded</exclude>\n                           </excludes>\n                        </configuration>\n                    </execution>\n                </executions>\n            </plugin>\n```\n</details>\n\nTo run diktat in **only-check** mode use command `$ mvn diktat:check@diktat`.\nTo run diktat in **autocorrect** mode use command `$ mvn diktat:fix@diktat`.\n\nRequesting a specific _Maven_ `executionId` on the command line (the trailing\n`diktat` in the above example) may be essential in these cases:\n\n  * In your `pom.xml`, you have multiple executions with different\n    configurations (e. g.: multiple rule sets):\n    <details>\n\n    ```xml\n    <executions>\n\n        <execution>\n            <id>diktat-basic</id>\n            <configuration>\n                <diktatConfigFile>diktat-analysis.yml</diktatConfigFile>\n            </configuration>\n        </execution>\n\n        <execution>\n            <id>diktat-advanced</id>\n            <configuration>\n                <diktatConfigFile>diktat-analysis-advanced.yml</diktatConfigFile>\n            </configuration>\n        </execution>\n\n    </executions>\n    ```\n    </details>\n  * Your YAML file with DiKTat rules has a non-default name and/or resides in a\n    non-default location:\n    <details>\n\n    ```xml\n    <executions>\n        <execution>\n            <id>diktat</id>\n            <configuration>\n                <diktatConfigFile>/non/default/rule-set-file.yml</diktatConfigFile>\n            </configuration>\n        </execution>\n    </executions>\n    ```\n    </details>\n\n    * You can omit the `diktatConfigFile` or if it points to non-existed file\n      then DiKTat runs with default configuration.\n\nIf you omit the `executionId`:\n\n```console\n$ mvn diktat:check\n```\n\n&mdash; the plug-in will use the default configuration and search for\n`diktat-analysis.yml` file in the project directory (you can still customize the\nrule sets by editing the YAML file).\n\n## Run with Gradle using diktat-gradle-plugin\nRequires a gradle version no lower than 7.0\n\nYou can see how the plugin is configured in our examples:\n- [Kotlin DSL](examples/gradle-kotlin-dsl/build.gradle.kts)\n- [Kotlin DSL for multi-module project](examples/gradle-kotlin-dsl-multiproject/build.gradle.kts)\n- [Groovy DSL](examples/gradle-groovy-dsl/build.gradle)\n\n<details>\n<summary>Add this plugin to your `build.gradle.kts`:</summary>\n\n```kotlin\nplugins {\n    id(\"com.saveourtool.diktat\") version \"2.0.0\"\n}\n```\n\n> _**Note**_ If you want to apply the plugin to multi-module projects\"\n> ```kotlin\n> import com.saveourtool.diktat.plugin.gradle.DiktatGradlePlugin\n>\n> plugins {\n>     id(\"com.saveourtool.diktat\") version \"2.0.0\" apply false\n> }\n>\n> allprojects {\n>     apply<DiktatGradlePlugin>()\n> }\n> ```\n\nYou can then configure diktat using `diktat` extension:\n```kotlin\ndiktat {\n    inputs {\n        include(\"src/**/*.kt\")  // path matching this pattern (per PatternFilterable) that will be checked by diktat\n        exclude(\"src/test/kotlin/excluded/**\")  // path matching this pattern will not be checked by diktat\n    }\n    debug = true  // turn on debug logging\n}\n```\n\nAlso in `diktat` extension you can configure different reporters and their output. You can specify `json`, `html`, `sarif`, `plain` (default).\nIf `output` is set, it should be a file path. If not set, results will be printed to stdout.\nYou can specify multiple reporters.\nIf no reporter is specified, `plain` will be used with `stdout` as output.\n```kotlin\ndiktat {\n    reporters {\n        plain()\n        json()\n        html {\n            output = file(\"someFile.html\")\n        }\n        // checkstyle()\n        // sarif()\n        // gitHubActions()\n    }\n}\n```\n</details>\n\nYou can run diktat checks using task `./gradlew diktatCheck` and automatically fix errors with task `./gradlew diktatFix`.\n\n## Run with Spotless\n[Spotless](https://github.com/diffplug/spotless) is a linter aggregator.\n\n### Gradle\nDiktat can be run via spotless-gradle-plugin since version 5.10.0\n\n<details>\n<summary>Add this plugin to your build.gradle.kts</summary>\n\n```kotlin\nplugins {\n   id(\"com.diffplug.spotless\") version \"5.10.0\"\n}\n\nspotless {\n   kotlin {\n      diktat()\n   }\n   kotlinGradle {\n      diktat()\n   }\n}\n```\n</details>\n\n<details>\n<summary>You can provide a version and configuration path manually as configFile.</summary>\n\n```kotlin\nspotless {\n   kotlin {\n      diktat(\"2.0.0\").configFile(\"full/path/to/diktat-analysis.yml\")\n   }\n}\n```\n</details>\n\n### Maven\nDiktat can be run via spotless-maven-plugin since version 2.8.0\n\n<details>\n<summary>Add this plugin to your pom.xml</summary>\n\n```xml\n<plugin>\n   <groupId>com.diffplug.spotless</groupId>\n   <artifactId>spotless-maven-plugin</artifactId>\n   <version>${spotless.version}</version>\n   <configuration>\n      <kotlin>\n         <diktat />\n      </kotlin>\n   </configuration>\n</plugin>\n```\n</details>\n\n<details>\n<summary>You can provide a version and configuration path manually as configFile</summary>\n\n```xml\n<diktat>\n  <version>2.0.0</version> <!-- optional -->\n  <configFile>full/path/to/diktat-analysis.yml</configFile> <!-- optional, configuration file path -->\n</diktat>\n```\n</details>\n\n## GitHub Integration\nWe suggest everyone to use common [\"sarif\"](https://docs.oasis-open.org/sarif/sarif/v2.0/sarif-v2.0.html) format as a `reporter` in CI/CD.\nGitHub has an [integration](https://docs.github.com/en/code-security/code-scanning/integrating-with-code-scanning/sarif-support-for-code-scanning)\nwith SARIF format and provides you a native reporting of diktat issues in Pull Requests.\n\n![img.png](example.png)\n\n<details>\n<summary> Github Integration</summary>\n1) Add the following configuration to your project's setup for GitHub Actions:\n\nGradle Plugin:\n```text\n    githubActions = true\n```\n\nMaven Plugin (pom.xml):\n```xml\n    <githubActions>true</githubActions>\n```\n\nMaven Plugin (cli options):\n```text\nmvn -B diktat:check@diktat -Ddiktat.githubActions=true\n```\n\n2) Add the following code to your GitHub Action to upload diktat SARIF report (after it was generated):\n\n```yml\n      - name: Upload SARIF to Github using the upload-sarif action\n        uses: github/codeql-action/upload-sarif@v1\n        if: ${{ always() }}\n        with:\n          sarif_file: ${{ github.workspace }}\n```\n\n*Note*: `codeql-action/upload-sarif` limits the number of uploaded files at 15. If your project has more than 15 subprojects,\nthe limit will be exceeded and the step will fail. To solve this issue one can merge SARIF reports.\n\n`diktat-gradle-plugin` provides this capability with `mergeDiktatReports` task. This task aggregates reports of all diktat tasks\nof all Gradle project, which produce SARIF reports, and outputs the merged report into root project's build directory. Then this single\nfile can be used as an input for GitHub action:\n```yaml\nwith:\n    sarif_file: build/reports/diktat/diktat-merged.sarif\n```\n\n</details>\n\n## <a name=\"config\"></a> Customizations via `diktat-analysis.yml`\n\nIn Diktat we have supported `diktat-analysis.yml` that can be easily\nchanged and help in customization of your own rule set.\nIt has simple fields:\n`name` — name of the rule,\n`enabled` (true/false) — to enable or disable that rule (all rules are enabled by the default),\n`configuration` — a simple map of some extra unique configurations for this particular rule.\nFor example:\n\n```yaml\n- name: HEADER_MISSING_OR_WRONG_COPYRIGHT\n  # all rules are enabled by the default. To disable add 'enabled: false' to the config.\n  enabled: true\n  configuration:\n    isCopyrightMandatory: true\n    copyrightText: Copyright (c) Jeff Lebowski, 2012-2020. All rights reserved.\n```\nNote, that you can specify and put `diktat-analysis.yml` that contains configuration of diktat in the parent directory of your project on the same level where `build.gradle/pom.xml` is stored. \\\nSee default configuration in [diktat-analysis.yml](diktat-rules/src/main/resources/diktat-analysis.yml) \\\nAlso see [the list of all rules supported by diKTat](info/available-rules.md).\n\n\n## <a name=\"suppress\"></a> Suppress warnings/inspections\n\n<details>\n<summary>Suppress warnings on individual code blocks</summary>\nIn addition to enabling/disabling warning globally via config file (`enable = false`), you can suppress warnings\nby adding `@Suppress` annotation on individual code blocks or `@file:Suppress()` annotation on a file-level.\n\nFor example:\n\n``` kotlin\n@Suppress(\"FUNCTION_NAME_INCORRECT_CASE\")\nclass SomeClass {\n    fun methODTREE(): String {\n\n    }\n}\n```\n</details>\n\n<details>\n<summary>Disable all inspections on selected code blocks</summary>\nAlso you can suppress **all** warnings by adding `@Suppress(\"diktat\")` annotation on individual code blocks.\n\nFor example:\n\n``` kotlin\n@Suppress(\"diktat\")\nclass SomeClass {\n    fun methODTREE(): String {\n\n    }\n}\n```\n</details>\n\n<details>\n<summary>ignoreAnnotated: disable inspections on blocks with predefined annotation</summary>\nIn the `diktat-analysis.yml` file for each inspection it is possible to define a list of annotations that will cause\ndisabling of the inspection on that particular code block:\n\n```yaml\n- name: HEADER_NOT_BEFORE_PACKAGE\n  enabled: true\n  ignoreAnnotated: [MyAnnotation, Compose, Controller]\n```\n</details>\n\n<details>\n<summary>Suppress groups of inspections by chapters</summary>\nIt is easy to suppress even groups of inspections in diKTat.\n\nThese groups are linked to chapters of [Codestyle](info/guide/diktat-coding-convention.md).\n\nTo disable chapters, you will need to add the following configuration to common configuration (`- name: DIKTAT_COMMON`):\n```yaml\n    disabledChapters: \"1, 2, 3\"\n```\n\nMapping of inspections to chapters can be found in [Groups of Inspections](info/rules-mapping.md).\n</details>\n\n## Running against the baseline\nWhen setting up code style analysis on a large existing project, one often doesn't have an ability to fix all findings at once.\nTo allow gradual adoption, diktat and ktlint support baseline mode. When running ktlint for the first time with active baseline,\nthe baseline file will be generated. It is a xml file with a complete list of findings by the tool. On later invocations,\nonly the findings that are not in the baseline file will be reported. Baseline can be activated with CLI flag:\n```bash\n./diktat --baseline=diktat-baseline.xml **/*.kt\n```\nor with corresponding configuration options in maven or gradle plugins. Baseline report is intended to be added into the VCS,\nbut it can be removed and re-generated later, if needed.\n\n## Contribution\nSee our [Contributing Policy](CONTRIBUTING.md) and [Code of Conduct](CODE_OF_CONDUCT.md)\n\n## Kotlin Coding Style Guide (Diktat Code Style), v.1.0.0\n\nI [Preface](#c0)\n* [I.I Purpose of this document](#c0.1)\n* [I.II General principles](#c0.2)\n* [I.III Terminology](#c0.3)\n* [I.IV Exceptions](#c0.4)\n\n[1. Naming](#c1)\n\n* [1.1 Identifiers](#c1.1)\n* [1.2 Packages](#c1.2)\n* [1.3 Classes, enumerations, interfaces](#c1.3)\n* [1.4 Functions](#c1.4)\n* [1.5 Constants](#c1.5)\n* [1.6 Non-constant fields (variables)](#c1.6)\n    * [1.6.1 Non-constant field name](#r1.6.1)\n    * [1.6.2 Boolean variable names with negative meaning](#r1.6.2)\n\n[2. Comments](#c2)\n* [2.1 General form of Kdoc](#c2.1)\n    * [2.1.1 Using KDoc for the public, protected, or internal code elements](#r2.1.1)\n    * [2.1.2 Describing methods that have arguments, a return value, or can throw an exception in the KDoc block](#r2.1.2)\n    * [2.1.3 Only one space between the Kdoc tag and content. Tags are arranged in the order.](#r2.1.3)\n* [2.2 Adding comments on the file header](#c2.2)\n* [2.3 Comments on the function header](#c2.3)\n* [2.4 Code comments](#c2.4)\n    * [2.4.1 Add a blank line between the body of the comment and Kdoc tag-blocks](#r2.4.1)\n    * [2.4.2 Do not comment on unused code blocks](#r2.4.2)\n    * [2.4.3 Code delivered to the client should not contain TODO/FIXME comments](#r2.4.3)\n\n[3. General formatting (typesetting)](#c3)\n* [3.1 File-related rules](#c3.1)\n    * [3.1.1 Avoid files that are too long](#r3.1.1)\n    * [3.1.2 Code blocks in the source file should be separated by one blank line](#r3.1.2)\n    * [3.1.3 Import statements order](#r3.1.3)\n    * [3.1.4 Order of declaration parts of class-like code structures](#r3.1.4)\n    * [3.1.5 Order of declaration of top-level code structures](#r3.1.5)\n* [3.2 Braces](#c3.2)\n    * [3.2.1 Using braces in conditional statements and loop blocks](#r3.2.1)\n    * [3.2.2 Opening braces are placed at the end of the line in *non-empty* blocks and block structures](#r3.2.2)\n* [3.3 Indentation](#c3.3)\n* [3.4 Empty blocks](#c3.4)\n* [3.5 Line length](#c3.5)\n* [3.6 Line breaks (newlines)](#c3.6)\n    * [3.6.1 Each line can have a maximum of one statement](#r3.6.1)\n    * [3.6.2 Rules for line-breaking](#r3.6.2)\n* [3.7 Using blank lines](#c3.7)\n* [3.8 Horizontal space](#c3.8)\n    * [3.8.1 Usage of whitespace for code separation](#r3.8.1)\n    * [3.8.2 No spaces for horizontal alignment](#r3.8.2)\n* [3.9 Enumerations](#c3.9)\n* [3.10 Variable declaration](#c3.10)\n    * [3.10.1 Declare one variable per line](#r3.10.1)\n    * [3.10.2 Variables should be declared near the line where they are first used](#r3.10.2)\n* [3.11 'When' expression](#c3.11)\n* [3.12 Annotations](#c3.12)\n* [3.13 Block comments](#c3.13)\n* [3.14 Modifiers and constant values](#c3.14)\n    * [3.14.1 Declaration with multiple modifiers](#r3.14.1)\n    * [3.14.2 Separate long numerical values with an underscore](#r3.14.2)\n* [3.15 Strings](#c3.15)\n    * [3.15.1 Concatenation of Strings](#r3.15.1)\n    * [3.15.2 String template format](#r3.15.2)\n* [3.16 Conditional statements](#c3.16)\n    * [3.16.1 Collapsing redundant nested if-statements](#r3.16.1)\n    * [3.16.2 Too complex conditions](#r3.16.2)\n\n[4. Variables and types](#c4)\n* [4.1 Variables](#c4.1)\n    * [4.1.1 Do not use Float and Double types when accurate calculations are needed](#r4.1.1)\n    * [4.1.2 Comparing numeric float type values](#r4.1.2)\n    * [4.1.3 Try to use 'val' instead of 'var' for variable declaration [SAY_NO_TO_VAR]](#r4.1.3)\n* [4.2 Types](#c4.2)\n    * [4.2.1 Use Contracts and smart cast as much as possible](#r4.2.1)\n    * [4.2.2 Try to use type alias to represent types making code more readable](#r4.2.2)\n* [4.3 Null safety and variable declarations](#c4.3)\n    * [4.3.1 Avoid declaring variables with nullable types, especially from Kotlin stdlib](#r4.3.1)\n    * [4.3.2 Variables of generic types should have an explicit type declaration](#r4.3.2)\n    * [4.3.3 Null-safety](#r4.3.3)\n\n[5. Functions](#c5)\n* [5.1 Function design](#c5.1)\n    * [5.1.1 Avoid functions that are too long ](#r5.1.1)\n    * [5.1.2 Avoid deep nesting of function code blocks, limiting to four levels](#r5.1.2)\n    * [5.1.3 Avoid using nested functions](#r5.1.3)\n    * [5.1.4 Negated function calls](#r5.1.4)\n* [5.2 Function arguments](#c5.2)\n    * [5.2.1 The lambda parameter of the function should be placed at the end of the argument list](#r5.2.1)\n    * [5.2.2 Number of function parameters should be limited to five](#r5.2.2)\n    * [5.2.3 Use default values for function arguments instead of overloading them](#r5.2.3)\n    * [5.2.4 Synchronizing code inside asynchronous code](#r5.2.4)\n    * [5.2.5 Long lambdas should have explicit parameters](#r5.2.5)\n    * [5.2.6 Avoid using unnecessary, custom label](#r5.2.6)\n\n[6. Classes, interfaces, and extension functions](#c6)\n* [6.1 Classes](#c6.1)\n    * [6.1.1 Denoting a class with a single constructor](#r6.1.1)\n    * [6.1.2 Prefer data classes instead of classes without any functional logic](#r6.1.2)\n    * [6.1.3 Do not use the primary constructor if it is empty or useless](#r6.1.3)\n    * [6.1.4 Do not use redundant init blocks in your class](#r6.1.4)\n    * [6.1.5 Explicit supertype qualification](#r6.1.5)\n    * [6.1.6 Abstract class should have at least one abstract method](#r6.1.6)\n    * [6.1.7 When using the \"implicit backing property\" scheme, the name of real and back property should be the same](#r6.1.7)\n    * [6.1.8 Avoid using custom getters and setters](#r6.1.8)\n    * [6.1.9 Never use the name of a variable in the custom getter or setter (possible_bug)](#r6.1.9)\n    * [6.1.10 No trivial getters and setters are allowed in the code](#r6.1.10)\n    * [6.1.11 Use 'apply' for grouping object initialization](#r6.1.11)\n    * [6.1.12 Prefer Inline classes when a class has a single property](#r6.1.12)\n* [6.2 Extension functions](#c6.2)\n    * [6.2.1 Use extension functions for making logic of classes less coupled](#r6.2.1)\n    * [6.2.2 No extension functions with the same name and signature if they extend base and inheritor classes (possible_bug)](#r6.2.2)\n    * [6.2.3 Don't use extension functions for the class in the same file](#r6.2.3)\n* [6.3 Interfaces](#c6.3)\n* [6.4 Objects](#c6.4)\n    * [6.4.1 Instead of using utility classes/objects, use extensions](#r6.4.1)\n    * [6.4.2 Objects should be used for Stateless Interfaces](#r6.4.2)\n* [6.5 Kts Files](#c6.5)\n    * [6.5.1 kts files should wrap logic into top-level scope](#r6.5.1)\n\n## <a name=\"c0\"></a> Preface\n <!-- =============================================================================== -->\n### <a name=\"c0.1\"></a> Purpose of this document\n\nThe purpose of this document is to provide a specification that software developers could reference to enhance their ability to write consistent, easy-to-read, and high-quality code.\nSuch a specification will ultimately improve software development efficiency and product competitiveness.\nFor the code to be considered high-quality, it must entail the following characteristics:\n1.\tSimplicity\n2.\tMaintainability\n3.\tReliability\n4.\tTestability\n5.\tEfficiency\n6.\tPortability\n7.\tReusability\n\n\n<!-- =============================================================================== -->\n### <a name=\"c0.2\"></a> General principles\n\nLike other modern programming languages, Kotlin is an advanced programming language that complies with the following general principles:\n1.\tClarity — a necessary feature of programs that are easy to maintain and refactor.\n2.\tSimplicity — a code is easy to understand and implement.\n3.\tConsistency — enables a code to be easily modified, reviewed, and understood by the team members. Unification is particularly important when the same team works on the same project, utilizing similar styles enabling a code to be easily modified, reviewed, and understood by the team members.\n\nAlso, we need to consider the following factors when programming on Kotlin:\n\n1. Writing clean and simple Kotlin code\n\n   Kotlin combines two of the main programming paradigms: functional and object-oriented.\n   Both of these paradigms are trusted and well-known software engineering practices.\n   As a young programming language, Kotlin is built on top of well-established languages such as Java, C++, C#, and Scala.\n   This enables Kotlin to introduce many features that help a developer write cleaner, more readable code while also reducing the number of complex code structures. For example, type and null safety, extension functions, infix syntax, immutability, val/var differentiation, expression-oriented features, \"when\" statements, much easier work with collections, type auto conversion, and other syntactic sugar.\n\n2. Following Kotlin idioms\n\n   The author of Kotlin, Andrey Breslav, mentioned that Kotlin is both pragmatic and practical, but not academic.\n   Its pragmatic features enable ideas to be transformed into real working software easily. Kotlin is closer to natural languages than its predecessors, and it implements the following design principles: readability, reusability, interoperability, security, and tool-friendliness (https://blog.jetbrains.com/kotlin/2018/10/kotlinconf-2018-announcements/).\n\n3. Using Kotlin efficiently\n\n   Some Kotlin features can help you to write higher-performance code: including rich coroutine library, sequences, inline functions/classes, arrays of basic types, tailRec, and CallsInPlace of contract.\n\n<!-- =============================================================================== -->\n### <a name=\"c0.3\"></a> Terminology\n\n**Rules** — conventions that should be followed when programming.\n\n**Recommendations** — conventions that should be considered when programming.\n\n**Explanation** — necessary explanations of rules and recommendations.\n\n**Valid Example** — recommended examples of rules and recommendations.\n\n**Invalid Example** — not recommended examples of rules and recommendations.\n\nUnless otherwise stated, this specification applies to versions 1.3 and later of Kotlin.\n\n<!-- =============================================================================== -->\n### <a name=\"c0.4\"></a> Exceptions\n\nEven though exceptions may exist, it is essential to understand why rules and recommendations are needed.\nDepending on a project situation or personal habits, you can break some of the rules. However, remember that one exception may lead to many and eventually can destroy code consistency. As such, there should be very few exceptions.\nWhen modifying open-source code or third-party code, you can choose to use the code style from this open-source project (instead of using the existing specifications) to maintain consistency.\nSoftware that is directly based on the Android native operating system interface, such as the Android Framework, remains consistent with the Android style.\n# <a name=\"c1\"></a> 1. Naming\nIn programming, it is not always easy to meaningfully and appropriately name variables, functions, classes, etc. Using meaningful names helps to clearly express your code's main ideas and functionality and avoid misinterpretation, unnecessary coding and decoding, \"magic\" numbers, and inappropriate abbreviations.\n\nNote: The source file encoding format (including comments) must be UTF-8 only. The ASCII horizontal space character (0x20, that is, space) is the only permitted whitespace character. Tabs should not be used for indentation.\n\n<!-- =============================================================================== -->\n### <a name=\"c1.1\"></a> 1.1 Identifiers\nThis section describes the general rules for naming identifiers.\n#### <a name=\"r1.1.1\"></a> 1.1.1 Identifiers naming conventions\n\nFor identifiers, use the following naming conventions:\n1.\tAll identifiers should use only ASCII letters or digits, and the names should match regular expressions `\\w{2,64}`.\n      Explanation: Each valid identifier name should match the regular expression `\\w{2,64}`.\n      `{2,64}` means that the name length is 2 to 64 characters, and the length of the variable name should be proportional to its life range, functionality, and responsibility.\n      Name lengths of less than 31 characters are generally recommended. However, this depends on the project. Otherwise, a class declaration with generics or inheritance from a superclass can cause line breaking.\n      No special prefix or suffix should be used in names. The following examples are inappropriate names: name_, mName, s_name, and kName.\n\n2.\tChoose file names that would describe the content. Use camel case (PascalCase) and `.kt` extension.\n\n3.\tTypical examples of naming:\n\n| Meaning | Correct |Incorrect|\n| ---- | ---- | ---- |\n| \"XML Http Request\" | XmlHttpRequest | XMLHTTPRequest |\n| \"new customer ID\" | newCustomerId | newCustomerID |\n| \"inner stopwatch\" | innerStopwatch | innerStopWatch |\n| \"supports IPv6 on iOS\" | supportsIpv6OnIos | supportsIPv6OnIOS |\n| \"YouTube importer\" | YouTubeImporter | YoutubeImporter |\n\n4.\tThe usage of (``) and free naming for functions and identifiers are prohibited. For example, the following code is not recommended:\n\n```kotlin\nval `my dummy name-with-minus` = \"value\"\n```\n\nThe only exception is function names in `Unit tests.`\n\n5.\tBackticks (``) should not be used for identifiers, except the names of test methods (marked with @Test annotation):\n```kotlin\n @Test fun `my test`() { /*...*/ }\n```\n6.  The following table contains some characters that may cause confusion. Be careful when using them as identifiers. To avoid issues, use other names instead.\n\n| Expected      | Confusing name           | Suggested name   |\n| ------------- | ------------------------ | ---------------- |\n| 0 (zero)      | O, D                     | obj, dgt         |\n| 1 (one)       | I, l                     | it, ln, line     |\n| 2 (two)       | Z                        | n1, n2           |\n| 5 (five)      | S                        | xs, str          |\n| 6 (six)       | e                        | ex, elm          |\n| 8 (eight)     | B                        | bt, nxt          |\n| n,h           | h,n                      | nr, head, height |\n| rn, m         | m,rn                     | mbr, item        |\n\n**Exceptions:**\n- The i,j,k variables used in loops are part of the industry standard. One symbol can be used for such variables.\n- The `e` variable can be used to catch exceptions in catch block: `catch (e: Exception) {}`\n- The Java community generally does not recommend the use of prefixes. However, when developing Android code, you can use the s and m prefixes for static and non-public non-static fields, respectively.\n  Note that prefixing can also negatively affect the style and the auto-generation of getters and setters.\n\n| Type | Naming style |\n| ---- | ---- |\n| Interfaces, classes, annotations, enumerated types, and object type names | Camel case, starting with a capital letter. Test classes have a Test suffix. The filename is 'TopClassName'.kt.  |\n| Class fields, local variables, methods, and method parameters | Camel case starting with a low case letter. Test methods can be underlined with '_'; the only exception is [backing properties](#r6.1.7).\n| Static constants and enumerated values | Only uppercase underlined with '_' |\n| Generic type variable | Single capital letter, which can be followed by a number, for example: `E, T, U, X, T2` |\n| Exceptions | Same as class names, but with a suffix Exception, for example: `AccessException` and `NullPointerException`|\n\n<!-- =============================================================================== -->\n### <a name=\"c1.2\"></a> 1.2 Packages\n\n#### <a name=\"r1.2.1\"></a> Rule 1.2.1 Package names dots\nPackage names are in lower case and separated by dots. Code developed within your company should start with `your.company.domain.` Numbers are permitted in package names.\nEach file should have a `package` directive.\nPackage names are all written in lowercase, and consecutive words are concatenated together (no underscores). Package names should contain both the product or module names and the department (or team) name to prevent conflicts with other teams.  Numbers are not permitted. For example: `org.apache.commons.lang3`, `xxx.yyy.v2`.\n\n**Exceptions:**\n\n- In certain cases, such as open-source projects or commercial cooperation, package names should not start with `your.company.domain.`\n- If the package name starts with a number or other character that cannot be used at the beginning of the Java/Kotlin package name, then underscores are allowed. For example: `com.example._123name`.\n- Underscores are sometimes permitted if the package name contains reserved Java/Kotlin keywords, such as `org.example.hyphenated_name`, `int_.example`.\n\n**Valid example**:\n```kotlin\npackage your.company.domain.mobilecontrol.views\n```\n\n<!-- =============================================================================== -->\n### <a name=\"c1.3\"></a> 1.3 Classes, enumerations, typealias, interfaces\nThis section describes the general rules for naming classes, enumerations, and interfaces.\n### <a name=\"r1.3.1\"></a> 1.3.1 Classes, enumerations, typealias, interface names use Camel case\nClasses, enumerations, and interface names use `UpperCamelCase` nomenclature. Follow the naming rules described below:\n1.\tA class name is usually a noun (or a noun phrase) denoted using the camel case nomenclature, such as UpperCamelCase. For example: `Character` or `ImmutableList`.\n      An interface name can also be a noun or noun phrase (such as `List`) or an adjective or adjective phrase (such as `Readable`).\n      Note that verbs are not used to name classes. However, nouns (such as `Customer`, `WikiPage`, and `Account`) can be used. Try to avoid using vague words such as `Manager` and `Process`.\n\n2.\tTest classes start with the name of the class they are testing and end with 'Test'. For example, `HashTest` or `HashIntegrationTest`.\n\n**Invalid example**:\n```kotlin\nclass marcoPolo {}\nclass XMLService {}\ninterface TAPromotion {}\nclass info {}\n```\n\n**Valid example**:\n```kotlin\nclass MarcoPolo {}\nclass XmlService {}\ninterface TaPromotion {}\nclass Order {}\n```\n\n<!-- =============================================================================== -->\n### <a name=\"c1.4\"></a> 1.4 Functions\nThis section describes the general rules for naming functions.\n### <a name=\"r1.4.1\"></a> 1.4.1 Function names should be in camel case\nFunction names should use `lowerCamelCase` nomenclature. Follow the naming rules described below:\n1.\tFunction names are usually verbs or verb phrases denoted with the camel case nomenclature (`lowerCamelCase`).\n      For example: `sendMessage`, `stopProcess`, or `calculateValue`.\n      To name functions, use the following formatting rules:\n\na) To get, modify, or calculate a certain value: get + non-boolean field(). Note that the Kotlin compiler automatically generates getters for some classes, applying the special syntax preferred for the 'get' fields: kotlin private val field: String get() { }. kotlin private val field: String get() { }.\n```kotlin\nprivate val field: String\nget() {\n}\n```\nNote: The calling property access syntax is preferred to call getter directly. In this case, the Kotlin compiler automatically calls the corresponding getter.\n\nb) `is` + boolean variable name()\n\nc) `set` + field/attribute name(). However, note that the syntax and code generation for Kotlin are completely the same as those described for the getters in point a.\n\nd) `has` + Noun / adjective ()\n\ne) verb()\nNote: Note: Verb are primarily used for the action objects, such as `document.print ()`\n\nf) verb + noun()\n\ng) The Callback function allows the names that use the preposition + verb format, such as: `onCreate()`, `onDestroy()`, `toString()`.\n\n**Invalid example**:\n\n```kotlin\nfun type(): String\nfun Finished(): Boolean\nfun visible(boolean)\nfun DRAW()\nfun KeyListener(Listener)\n```\n\n**Valid example**:\n\n```kotlin\nfun getType(): String\nfun isFinished(): Boolean\nfun setVisible(boolean)\nfun draw()\nfun addKeyListener(Listener)\n```\n\n2.\tAn underscore (`_`) can be included in the JUnit test function name and should be used as a separator. Each logical part is denoted in `lowerCamelCase`, for example, a typical pattern of using underscore: `pop_emptyStack`.\n<!-- =============================================================================== -->\n### <a name=\"c1.5\"></a> 1.5 Constants\nThis section describes the general rules for naming constraints.\n### <a name=\"r1.5.1\"></a> 1.5.1 Using UPPER case and underscore characters in a constraint name\nConstant names should be in UPPER case, words separated by underscore. The general constant naming conventions are listed below:\n1. Constants are attributes created with the `const` keyword or top-level/`val` local variables of an object that holds immutable data. In most cases, constants can be identified as a `const val` property from the `object`/`companion object`/file top level. These variables contain fixed constant values that typically should never be changed by programmers. This includes basic types, strings, immutable types, and immutable collections of immutable types. The value is not constant for the object, which state can be changed.\n2. Constant names should contain only uppercase letters separated by an underscores. They should have a val or const val modifier to make them final explicitly. In most cases, if you need to specify a constant value, then you need to create it with the \"const val\" modifier. Note that not all `val` variables are constants.\n3. Objects with immutable content, such as `Logger` and `Lock`, can be in uppercase as constants or have camel case as regular variables.\n4. Use meaningful constants instead of `magic numbers`. SQL or logging strings should not be treated as magic numbers, nor should they be defined as string constants.\n   Magic constants, such as `NUM_FIVE = 5` or `NUM_5 = 5` should not be treated as constants. This is because mistakes will easily be made if they are changed to `NUM_5 = 50` or 55.\n   These constants typically represent business logic values, such as measures, capacity, scope, location, tax rate, promotional discounts, and power base multiples in algorithms.\n   You can avoid using magic numbers with the following method:\n- Using library functions and APIs. For example, instead of checking that `size == 0`, use `isEmpty()` function. To work with `time`, use built-ins from `java.time API`.\n- Enumerations can be used to name patterns. Refer to [Recommended usage scenario for enumeration in 3.9](#c3.9).\n\n**Invalid example**:\n\n```kotlin\nvar int MAXUSERNUM = 200;\nval String sL = \"Launcher\";\n```\n\n**Valid example**:\n\n```kotlin\nconst val int MAX_USER_NUM = 200;\nconst val String APPLICATION_NAME = \"Launcher\";\n```\n\n<!-- =============================================================================== -->\n### <a name=\"c1.6\"></a> 1.6 Non-constant fields (variables)\nThis section describes the general rules for naming variables.\n### <a name=\"r1.6.1\"></a> 1.6.1 Non-constant field name\nNon-constant field names should use camel case and start with a lowercase letter.\nA local variable cannot be treated as constant even if it is final and immutable. Therefore, it should not use the preceding rules. Names of collection type variables (sets, lists, etc.) should contain plural nouns.\nFor example: `var namesList: List<String>`\n\nNames of non-constant variables should use `lowerCamelCase`. The name of the final immutable field used to store the singleton object can use the same camel case notation.\n\n**Invalid example**:\n```kotlin\ncustomername: String\nuser: List<String> = listof()\n```\n\n**Valid example**:\n```kotlin\nvar customerName: String\nval users: List<String> = listOf();\nval mutableCollection: MutableSet<String> = HashSet()\n```\n\n### <a name=\"r1.6.2\"></a> 1.6.2 Boolean variable names with negative meaning\n\nAvoid using Boolean variable names with a negative meaning. When using a logical operator and name with a negative meaning, the code may be difficult to understand, which is referred to as the \"double negative\".\nFor instance, it is not easy to understand the meaning of !isNotError.\nThe JavaBeans specification automatically generates isXxx() getters for attributes of Boolean classes.\nHowever, not all methods returning Boolean type have this notation.\nFor Boolean local variables or methods, it is highly recommended that you add non-meaningful prefixes, including is (commonly used by JavaBeans), has, can, should, and must. Modern integrated development environments (IDEs) such as Intellij are already capable of doing this for you when you generate getters in Java. For Kotlin, this process is even more straightforward as everything is on the byte-code level under the hood.\n\n**Invalid example**:\n```kotlin\nval isNoError: Boolean\nval isNotFound: Boolean\nfun empty()\nfun next();\n```\n\n**Valid example**:\n```kotlin\nval isError: Boolean\nval isFound: Boolean\nval hasLicense: Boolean\nval canEvaluate: Boolean\nval shouldAbort: Boolean\nfun isEmpty()\nfun hasNext()\n```\n# <a name=\"c2\"></a> 2. Comments\n\nThe best practice is to begin your code with a summary, which can be one sentence.\nTry to balance between writing no comments at all and obvious commentary statements for each line of code.\nComments should be accurately and clearly expressed, without repeating the name of the class, interface, or method.\nComments are not a solution to the wrong code. Instead, you should fix the code as soon as you notice an issue or plan to fix it (by entering a TODO comment, including a Jira number).\nComments should accurately reflect the code's design ideas and logic and further describe its business logic.\nAs a result, other programmers will be able to save time when trying to understand the code.\nImagine that you are writing the comments to help yourself to understand the original ideas behind the code in the future.\n\n### <a name=\"c2.1\"></a> 2.1 General form of Kdoc\n\nKDoc is a combination of JavaDoc's block tags syntax (extended to support specific constructions of Kotlin) and Markdown's inline markup.\nThe basic format of KDoc is shown in the following example:\n\n```kotlin\n /**\n * There are multiple lines of KDoc text,\n * Other ...\n */\nfun method(arg: String) {\n    // ...\n}\n```\n\nIt is also shown in the following single-line form:\n\n```kotlin\n /** Short form of KDoc. */\n```\nUse a single-line form when you store the entire KDoc block in one line (and there is no KDoc mark @XXX). For detailed instructions on how to use KDoc, refer to [Official Document](https://docs.oracle.com/en/Kotlin/Kotlinse/11/tools/KDoc.html).\n\n#### <a name=\"r2.1.1\"></a> 2.1.1 Using KDoc for the public, protected, or internal code elements\n\nAt a minimum, KDoc should be used for every public, protected, or internal decorated class, interface, enumeration, method, and member field (property).\nOther code blocks can also have KDocs if needed.\nInstead of using comments or KDocs before properties in the primary constructor of a class - use `@property` tag in a KDoc of a class.\nAll properties of the primary constructor should also be documented in a KDoc with a `@property` tag.\n\n\n**Incorrect example:**\n```kotlin\n/**\n * Class description\n */\nclass Example(\n /**\n  * property description\n  */\n  val foo: Foo,\n  // another property description\n  val bar: Bar\n)\n```\n\n**Correct example:**\n```kotlin\n/**\n * Class description\n * @property foo property description\n * @property bar another property description\n */\nclass Example(\n  val foo: Foo,\n  val bar: Bar\n)\n```\n- Don't use Kdoc comments inside code blocks as block comments\n\n**Incorrect Example:**\n\n```kotlin\nclass Example {\n  fun doGood() {\n    /**\n     * wrong place for kdoc\n     */\n    1 + 2\n  }\n}\n```\n\n**Correct Example:**\n\n```kotlin\nclass Example {\n  fun doGood() {\n    /*\n     * right place for block comment\n    */\n    1 + 2\n  }\n}\n```\n\n**Exceptions:**\n\n* For setters/getters of properties, obvious comments (like `this getter returns field`) are optional. Note that Kotlin generates simple `get/set` methods under the hood.\n\n* It is optional to add comments for simple one-line methods, such as shown in the example below:\n```kotlin\nval isEmpty: Boolean\n    get() = this.size == 0\n```\n\nor\n\n```kotlin\nfun isEmptyList(list: List<String>) = list.size == 0\n```\n\n**Note:** You can skip KDocs for a method's override if it is almost the same as the superclass method.\n\n#### <a name=\"r2.1.2\"></a> 2.1.2 Describing methods that have arguments, a return value, or can throw an exception in the KDoc block\n\nWhen the method has such details as arguments, return value, or can throw exceptions, it must be described in the KDoc block (with @param, @return, @throws, etc.).\n\n**Valid examples:**\n\n ```kotlin\n/**\n * This is the short overview comment for the example interface.\n *     / * Add a blank line between the comment text and each KDoc tag underneath * /\n * @since 1.6\n */\n protected abstract class Sample {\n    /**\n     * This is a long comment with whitespace that should be split in\n     * comments on multiple lines if the line comment formatting is enabled.\n     *     / * Add a blank line between the comment text and each KDoc tag underneath * /\n     * @param fox A quick brown fox jumps over the lazy dog\n     * @return battle between fox and dog\n     */\n    protected abstract fun foo(Fox fox)\n     /**\n      * These possibilities include: Formatting of header comments\n      *     / * Add a blank line between the comment text and each KDoc tag underneath * /\n      * @return battle between fox and dog\n      * @throws ProblemException if lazy dog wins\n      */\n    protected fun bar() throws ProblemException {\n        // Some comments / * No need to add a blank line here * /\n        var aVar = ...\n\n        // Some comments  / * Add a blank line before the comment * /\n        fun doSome()\n    }\n }\n ```\n\n#### <a name=\"r2.1.3\"></a>2.1.3 Only one space between the Kdoc tag and content. Tags are arranged in the order.\n\nThere should be only one space between the Kdoc tag and content. Tags are arranged in the following order: @param, @return, and @throws.\n\nTherefore, Kdoc should contain the following:\n- Functional and technical description, explaining the principles, intentions, contracts, API, etc.\n- The function description and @tags (`implSpec`, `apiNote`, and `implNote`) require an empty line after them.\n- `@implSpec`: A specification related to API implementation, and it should let the implementer decide whether to override it.\n- `@apiNote`: Explain the API precautions, including whether to allow null and whether the method is thread-safe, as well as the algorithm complexity, input, and output range, exceptions, etc.\n- `@implNote`: A note related to API implementation, which implementers should keep in mind.\n- One empty line, followed by regular `@param`, `@return`, `@throws`, and other comments.\n- The conventional standard \"block labels\" are arranged in the following order: `@param`, `@return`, `@throws`.\n  Kdoc should not contain:\n- Empty descriptions in tag blocks. It is better not to write Kdoc than waste code line space.\n- There should be no empty lines between the method/class declaration and the end of Kdoc (`*/` symbols).\n- `@author` tag. It doesn't matter who originally created a class when you can use `git blame` or VCS of your choice to look through the changes history.\n  Important notes:\n- KDoc does not support the `@deprecated` tag. Instead, use the `@Deprecated` annotation.\n- The `@since` tag should be used for versions only. Do not use dates in `@since` tag, it's confusing and less accurate.\n\nIf a tag block cannot be described in one line, indent the content of the new line by *four spaces* from the `@` position to achieve alignment (`@` counts as one + three spaces).\n\n**Exception:**\n\nWhen the descriptive text in a tag block is too long to wrap, you can indent the alignment with the descriptive text in the last line. The descriptive text of multiple tags does not need to be aligned.\nSee [3.8 Horizontal space](#c3.8).\n\nIn Kotlin, compared to Java, you can put several classes inside one file, so each class should have a Kdoc formatted comment (as stated in rule 2.1).\nThis comment should contain @since tag. The right style is to write the application version when its functionality is released. It should be entered after the `@since` tag.\n\n**Examples:**\n\n```kotlin\n/**\n * Description of functionality\n *\n * @since 1.6\n */\n```\n\nOther KDoc tags (such as @param type parameters and @see.) can be added as follows:\n```kotlin\n/**\n * Description of functionality\n *\n * @apiNote: Important information about API\n *\n * @since 1.6\n */\n```\n\n### <a name=\"c2.2\"></a> 2.2 Adding comments on the file header\n\nThis section describes the general rules of adding comments on the file header.\n\n### <a name=\"r2.2.1\"></a> 2.2.1 Formatting of comments in the file header\n\nComments on the file header should be placed before the package name and imports. If you need to add more content to the comment, subsequently add it in the same format.\n\nComments on the file header must include copyright information, without the creation date and author's name (use VCS for history management).\nAlso, describe the content inside files that contain multiple or no classes.\n\nThe following examples for Huawei describe the format of the *copyright license*: \\\nChinese version: `版权所有 (c) 华为技术有限公司 2012-2020` \\\nEnglish version: `Copyright (c) Huawei Technologies Co., Ltd. 2012-2020. All rights reserved.`\n`2012` and `2020` are the years the file was first created and the current year, respectively.\n\nDo not place **release notes** in header, use VCS to keep track of changes in file. Notable changes can be marked in individual KDocs using `@since` tag with version.\n\nInvalid example:\n```kotlin\n/**\n * Release notes:\n * 2019-10-11: added class Foo\n */\n\nclass Foo\n```\n\nValid example:\n```kotlin\n/**\n * @since 2.4.0\n */\nclass Foo\n```\n\n- The **copyright statement** can use your company's subsidiaries, as shown in the below examples: \\\n  Chinese version: `版权所有 (c) 海思半导体 2012-2020` \\\n  English version: `Copyright (c) Hisilicon Technologies Co., Ltd. 2012-2020. All rights reserved.`\n\n- The copyright information should not be written in KDoc style or use single-line comments. It must start from the beginning of the file.\n  The following example is a copyright statement for Huawei, without other functional comments:\n\n```kotlin\n/*\n * Copyright (c) Huawei Technologies Co., Ltd. 2012-2020. All rights reserved.\n */\n```\n\nThe following factors should be considered when writing the file header or comments for top-level classes:\n- File header comments must start from the top of the file. If it is a top-level file comment, there should be a blank line after the last Kdoc `*/` symbol. If it is a comment for a top-level class, the class declaration should start immediately without using a newline.\n- Maintain a unified format. The specific format can be formulated by the project (for example, if you use an existing opensource project), and you need to follow it.\n- A top-level file-Kdoc must include a copyright and functional description, especially if there is more than one top-level class.\n- Do not include empty comment blocks. If there is no content after the option `@apiNote`, the entire tag block should be deleted.\n- The industry practice is not to include historical information in the comments. The corresponding history can be found in VCS (git, svn, etc.). Therefore, it is not recommended to include historical data in the comments of the Kotlin source code.\n\n### <a name=\"c2.3\"></a> 2.3 Comments on the function header\n\nComments on the function header are placed above function declarations or definitions. A newline should not exist between a function declaration and its Kdoc. Use the preceding <<c2.1,KDoc>> style rules.\n\nAs stated in Chapter 1, the function name should reflect its functionality as much as possible. Therefore, in the Kdoc, try to describe the functionality that is not mentioned in the function name.\nAvoid unnecessary comments on dummy coding.\n\nThe function header comment's content is optional, but not limited to function description, return value, performance constraints, usage, memory conventions, algorithm implementation, reentrant requirements, etc.\n\n### <a name=\"c2.4\"></a> 2.4 Code comments\n\nThis section describes the general rules of adding code comments.\n\n#### <a name=\"r2.4.1\"></a> 2.4.1 Add a blank line between the body of the comment and Kdoc tag-blocks.\n\nIt is a good practice to add a blank line between the body of the comment and Kdoc tag-blocks. Also, consider the following rules:\n- There must be one space between the comment character and the content of the comment.\n- There must be a newline between a Kdoc and the presiding code.\n- An empty line should not exist between a Kdoc and the code it is describing. You do not need to add a blank line before the first comment in a particular namespace (code block) (for example, between the function declaration and first comment in a function body).\n\n**Valid Examples:**\n\n```kotlin\n/**\n * This is the short overview comment for the example interface.\n *\n * @since 1.6\n */\n public interface Example {\n    // Some comments  /* Since it is the first member definition in this code block, there is no need to add a blank line here */\n    val aField: String = ...\n                     /* Add a blank line above the comment */\n    // Some comments\n    val bField: String = ...\n                      /* Add a blank line above the comment */\n    /**\n     * This is a long comment with whitespace that should be split in\n     * multiple line comments in case the line comment formatting is enabled.\n     *                /* blank line between description and Kdoc tag */\n     * @param fox A quick brown fox jumps over the lazy dog\n     * @return the rounds of battle of fox and dog\n     */\n    fun foo(Fox fox)\n                      /* Add a blank line above the comment */\n     /**\n      * These possibilities include: Formatting of header comments\n      *\n      * @return the rounds of battle of fox and dog\n      * @throws ProblemException if lazy dog wins\n      */\n    fun bar() throws ProblemException {\n        // Some comments  /* Since it is the first member definition in this range, there is no need to add a blank line here */\n        var aVar = ...\n\n        // Some comments  /* Add a blank line above the comment */\n        fun doSome()\n    }\n }\n```\n\n- Leave one single space between the comment on the right side of the code and the code.\n  If you use conditional comments in the `if-else-if` scenario, put the comments inside the `else-if` branch or in the conditional block, but not before the `else-if`. This makes the code more understandable.\n  When the if-block is used with curly braces, the comment should be placed on the next line after opening the curly braces.\n  Compared to Java, the `if` statement in Kotlin statements returns a value. For this reason, a comment block can describe a whole `if-statement`.\n\n**Valid examples:**\n\n```kotlin\n\nval foo = 100  // right-side comment\nval bar = 200  /* right-side comment */\n\n// general comment for the value and whole if-else condition\nval someVal = if (nr % 15 == 0) {\n    // when nr is a multiple of both 3 and 5\n    println(\"fizzbuzz\")\n} else if (nr % 3 == 0) {\n    // when nr is a multiple of 3, but not 5\n    // We print \"fizz\", only.\n    println(\"fizz\")\n} else if (nr % 5 == 0) {\n    // when nr is a multiple of 5, but not 3\n    // we print \"buzz\" only.\n    println(\"buzz\")\n} else {\n    // otherwise, we print the number.\n    println(x)\n}\n```\n\n- Start all comments (including KDoc) with a space after the first symbol (`//`, `/*`, `/**` and `*`)\n\n**Valid example:**\n\n```kotlin\nval x = 0  // this is a comment\n```\n\n#### <a name=\"r2.4.2\"></a> 2.4.2 Do not comment on unused code blocks\n\nDo not comment on unused code blocks, including imports. Delete these code blocks immediately.\nA code is not used to store history. Git, svn, or other VCS tools should be used for this purpose.\nUnused imports increase the coupling of the code and are not conducive to maintenance. The commented out code cannot be appropriately maintained.\nIn an attempt to reuse the code, there is a high probability that you will introduce defects that are easily missed.\nThe correct approach is to delete the unnecessary code directly and immediately when it is not used anymore.\nIf you need the code again, consider porting or rewriting it as changes could have occurred since you first commented on the code.\n\n#### <a name=\"r2.4.3\"></a>2.4.3 Code delivered to the client should not contain TODO/FIXME comments\n\nThe code officially delivered to the client typically should not contain TODO/FIXME comments.\n`TODO` comments are typically used to describe modification points that need to be improved and added. For example, refactoring FIXME comments are typically used to describe known defects and bugs that will be subsequently fixed and are not critical for an application.\nThey should all have a unified style to facilitate unified text search processing.\n\n**Example:**\n\n```kotlin\n// TODO(<author-name>): Jira-XXX - support new json format\n// FIXME: Jira-XXX - fix NPE in this code block\n```\n\nAt a version development stage, these annotations can be used to highlight the issues in the code, but all of them should be fixed before a new product version is released.\n# <a name=\"c3\"></a>3. General formatting (typesetting)\n<!-- =============================================================================== -->\n### <a name=\"c3.1\"></a> 3.1 File-related rules\nThis section describes the rules related to using files in your code.\n#### <a name=\"r3.1.1\"></a> 3.1.1 Avoid files that are too long\n\nIf the file is too long and complicated, it should be split into smaller files, functions, or modules. Files should not exceed 2000 lines (non-empty and non-commented lines).\nIt is recommended to horizontally or vertically split the file according to responsibilities or hierarchy of its parts.\nThe only exception to this rule is code generation - the auto-generated files that are not manually modified can be longer.\n\n#### <a name=\"r3.1.2\"></a> 3.1.2 Code blocks in the source file should be separated by one blank line\nA source file contains code blocks in the following order: copyright, package name, imports, and top-level classes. They should be separated by one blank line.\n\na) Code blocks should be in the following order:\n1.\tKdoc for licensed or copyrighted files\n2.\t`@file` annotation\n3.\tPackage name\n4.\tImport statements\n5.\tTop-class header and top-function header comments\n6.\tTop-level classes or functions\n\nb) Each of the preceding code blocks should be separated by a blank line.\n\nc) Import statements are alphabetically arranged, without using line breaks and wildcards ( wildcard imports - `*`).\n\nd) **Recommendation**: One `.kt` source file should contain only one class declaration, and its name should match the filename\n\ne) Avoid empty files that do not contain the code or contain only imports/comments/package name\n\nf) Unused imports should be removed\n#### <a name=\"r3.1.3\"></a> 3.1.3 Import statements order\n\nFrom top to bottom, the order is the following:\n1. Android\n2. Imports of packages used internally in your organization\n3. Imports from other non-core dependencies\n4. Java core packages\n5. kotlin stdlib\n\nEach category should be alphabetically arranged. Each group should be separated by a blank line. This style is compatible with  [Android import order](https://source.android.com/setup/contribute/code-style#order-import-statements).\n\n**Valid example**:\n```kotlin\nimport android.* // android\nimport androidx.* // android\nimport com.android.* // android\n\nimport com.your.company.* // your company's libs\nimport your.company.* // your company's libs\n\nimport com.fasterxml.jackson.databind.ObjectMapper // other third-party dependencies\nimport org.junit.jupiter.api.Assertions\n\nimport java.io.IOException // java core packages\nimport java.net.URL\n\nimport kotlin.system.exitProcess  // kotlin standard library\nimport kotlinx.coroutines.*  // official kotlin extension library\n```\n\n#### <a name=\"r3.1.4\"></a> 3.1.4 Order of declaration parts of class-like code structures\nThe declaration parts of class-like code structures (class, interface, etc.) should be in the following order: compile-time constants (for objects), class properties, late-init class properties, init-blocks, constructors, public methods, internal methods, protected methods, private methods, and companion object. Blank lines should separate their declaration.\nNotes:\n1.\tThere should be no blank lines between properties with the following **exceptions**: when there is a comment before a property on a separate line or annotations on a separate line.\n2.\tProperties with comments/Kdoc should be separated by a newline before the comment/Kdoc.\n3.\tEnum entries and constant properties (`const val`) in companion objects should be alphabetically arranged.\n\nThe declaration part of a class or interface should be in the following order:\n- Compile-time constants (for objects)\n- Properties\n- Late-init class properties\n- Init-blocks\n- Constructors\n- Methods or nested classes. Put nested classes next to the code they are used by.\n  If the classes are meant to be used externally, and are not referenced inside the class, put them after the companion object.\n- Companion object\n\n**Exception:**\nAll variants of a `private val` logger should be placed at the beginning of the class (`private val log`, `LOG`, `logger`, etc.).\n\n#### <a name=\"r3.1.5\"></a> 3.1.5 Order of declaration of top-level code structures\nKotlin allows several top-level declaration types: classes, objects, interfaces, properties and functions.\nWhen declaring more than one class or zero classes (e.g. only functions), as per rule [2.2.1](#r2.2.1), you should document the whole file in the header KDoc.\nWhen declaring top-level structures, keep the following order:\n1. Top-level constants and properties (following same order as properties inside a class: `const val`,`val`, `lateinit var`, `var`)\n2. typealiases (grouped by their visibility modifiers)\n2. Interfaces, classes and objects (grouped by their visibility modifiers)\n3. Extension functions\n4. Other functions\n\n**Note**:\nExtension functions shouldn't have receivers declared in the same file according to [rule 6.2.3](#r6.2.3)\n\nValid example:\n```kotlin\npackage com.saveourtool.diktat.example\n\nconst val CONSTANT = 42\n\nval topLevelProperty = \"String constant\"\n\ninternal typealias ExamplesHandler = (IExample) -> Unit\n\ninterface IExample\n\nclass Example : IExample\n\nprivate class Internal\n\nfun Other.asExample(): Example { /* ... */ }\n\nprivate fun Other.asInternal(): Internal { /* ... */ }\n\nfun doStuff() { /* ... */ }\n```\n\n**Note**:\nkotlin scripts (.kts) allow arbitrary code to be placed on the top level. When writing kotlin scripts, you should first declare all properties, classes\nand functions. Only then you should execute functions on top level. It is still recommended wrapping logic inside functions and avoid using top-level statements\nfor function calls or wrapping blocks of code in top-level scope functions like `run`.\n\nExample:\n```kotlin\n/* class declarations */\n/* function declarations */\nrun {\n    // call functions here\n}\n```\n\n<!-- =============================================================================== -->\n### <a name=\"c3.2\"></a> 3.2 Braces\nThis section describes the general rules of using braces in your code.\n#### <a name=\"r3.2.1\"></a> 3.2.1 Using braces in conditional statements and loop blocks\n\nBraces should always be used in `if`, `else`, `for`, `do`, and `while` statements, even if the program body is empty or contains only one statement. In special Kotlin `when` statements, you do not need to use braces for single-line statements.\n\n**Valid example:**\n\n```kotlin\nwhen (node.elementType) {\n    FILE -> {\n        checkTopLevelDoc(node)\n        checkSomething()\n     }\n    CLASS -> checkClassElements(node)\n}\n```\n**Exception:** The only exception is ternary operator in Kotlin (a single line `if () <> else <>` )\n\n**Invalid example:**\n\n```kotlin\nval value = if (string.isEmpty())  // WRONG!\n                0\n            else\n                1\n```\n\n**Valid example**:\n\n```kotlin\nval value = if (string.isEmpty()) 0 else 1  // Okay\n```\n\n```kotlin\nif (condition) {\n    println(\"test\")\n} else {\n    println(0)\n}\n```\n\n#### <a name=\"r3.2.2\"></a> 3.2.2  Opening braces are placed at the end of the line in *non-empty* blocks and block structures\nFor *non-empty* blocks and block structures, the opening brace is placed at the end of the line.\nFollow the K&R style (1TBS or OTBS) for *non-empty* code blocks with braces:\n- The opening brace and first line of the code block are on the same line.\n- The closing brace is on its own new line.\n- The closing brace can be followed by a newline character. The only exceptions are `else`, `finally`, and `while` (from `do-while` statement), or `catch` keywords.\n  These keywords should not be split from the closing brace by a newline character.\n\n**Exception cases**:\n\n1) For lambdas, there is no need to put a newline character after the first (function-related) opening brace. A newline character should appear only after an arrow (`->`) (see [point 5 of Rule 3.6.2](#r3.6.2)).\n\n```kotlin\narg.map { value ->\n    foo(value)\n}\n```\n\n2) for `else`/`catch`/`finally`/`while` (from `do-while` statement) keywords closing brace should stay on the same line:\n ```kotlin\ndo {\n    if (true) {\n        x++\n    } else {\n        x--\n    }\n} while (x > 0)\n```\n\n**Valid example:**\n\n ```kotlin\n        return arg.map { value ->\n            while (condition()) {\n                method()\n            }\n            value\n        }\n\n        return MyClass() {\n            @Override\n              fun method() {\n                if (condition()) {\n                    try {\n                        something()\n                    } catch (e: ProblemException) {\n                        recover()\n                    }\n                } else if (otherCondition()) {\n                    somethingElse()\n                } else {\n                    lastThing()\n                }\n            }\n        }\n ```\n\n<!-- =============================================================================== -->\n### <a name=\"c3.3\"></a> 3.3 Indentation\n\nOnly spaces are permitted for indentation, and each indentation should equal `four spaces` (tabs are not permitted).\nIf you prefer using tabs, simply configure them to change to spaces in your IDE automatically.\nThese code blocks should be indented if they are placed on the new line, and the following conditions are met:\n-\tThe code block is placed immediately after an opening brace.\n-\tThe code block is placed after each operator, including the assignment operator (`+`/`-`/`&&`/`=`/etc.)\n-\tThe code block is a call chain of methods:\n```kotlin\nsomeObject\n    .map()\n    .filter()\n```\n-  The code block is placed immediately after the opening parenthesis.\n-  The code block is placed immediately after an arrow in lambda:\n\n ```kotlin\narg.map { value ->\n    foo(value)\n}\n```\n\n**Exceptions**:\n1.\tArgument lists: \\\n      a) Eight spaces are used to indent argument lists (both in declarations and at call sites). \\\n      b) Arguments in argument lists can be aligned if they are on different lines.\n\n2.\tEight spaces are used if there is a newline after any binary operator.\n\n3.\tEight spaces are used for functional-like styles when the newline is placed before the dot.\n\n4.\tSupertype lists: \\\n      a) Four spaces are used if the colon before the supertype list is on a new line. \\\n      b) Four spaces are used before each supertype, and eight spaces are used if the colon is on a new line.\n\n**Note:** there should be an indentation after all statements such as `if`, `for`, etc. However, according to this code style, such statements require braces.\n\n```kotlin\nif (condition)\n    foo()\n```\n\n**Exceptions**:\n- When breaking the parameter list of a method/class constructor, it can be aligned with `8 spaces`. A parameter that was moved to a new line can be on the same level as the previous argument:\n\n```kotlin\nfun visit(\n        node: ASTNode,\n        autoCorrect: Boolean,\n        params: KtLint.ExperimentalParams,\n        emit: (offset: Int, errorMessage: String, canBeAutoCorrected: Boolean) -> Unit\n) {\n}\n```\n\n- Such operators as `+`/`-`/`*` can be indented with `8 spaces`:\n\n```kotlin\nval abcdef = \"my splitted\" +\n                \" string\"\n```\n\n- Opening and closing quotes in multiline string should have same indentation\n\n```kotlin\nlintMethod(\n            \"\"\"\n                    |val q = 1\n                    |\n            \"\"\".trimMargin()\n    )\n```\n\n- A list of supertypes should be indented with `4 spaces` if they are on different lines or with `8 spaces` if the leading colon is also on a separate line\n\n```kotlin\nclass A :\n    B()\n\nclass A\n    :\n        B()\n```\n\n<!-- =============================================================================== -->\n### <a name=\"c3.4\"></a> 3.4 Empty blocks\n\nAvoid empty blocks, and ensure braces start on a new line. An empty code block can be closed immediately on the same line and the next line. However, a newline is recommended between opening and closing braces `{}` (see the examples below.)\n\nGenerally, empty code blocks are prohibited; using them is considered a bad practice (especially for catch block).\nThey are appropriate for overridden functions, when the base class's functionality is not needed in the class-inheritor, for lambdas used as a function and for empty function in implementation of functional interface.\n```kotlin\noverride fun foo() {\n}\n```\n\n**Valid examples** (note once again that generally empty blocks are prohibited):\n\n```kotlin\nfun doNothing() {}\n\nfun doNothingElse() {\n}\n\nfun foo(bar: () -> Unit = {})\n```\n\n**Invalid examples:**\n```kotlin\ntry {\n  doSomething()\n} catch (e: Some) {}\n```\n\nUse the following valid code instead:\n```kotlin\ntry {\n   doSomething()\n} catch (e: Some) {\n}\n```\n\n<!-- =============================================================================== -->\n### <a name=\"c3.5\"></a> 3.5 Line length\n\nLine length should be less than 120 symbols. Otherwise, it should be split.\n\nIf `complex property` initializing is too long, It should be split into priorities: \\\n1. Logic Binary Expression (&&  ||) \\\n2. Comparison Binary Expression (> < == >= <= !=) \\\n3. Other types (Arithmetical and Bit operation) (+ - * / % >> << *= += -= /= %= ++ -- ! in !in etc)\n\n**Invalid example:**\n```kotlin\nval complexProperty = 1 + 2 + 3 + 4\n```\n**Valid example:**\n```kotlin\nval complexProperty = 1 + 2 +\n    3 + 4\n```\n\n**Invalid example:**\n```kotlin\nval complexProperty = (1 + 2 + 3 > 0) && ( 23 * 4 > 10 * 6)\n```\n**Valid example:**\n```kotlin\nval complexProperty = (1 + 2 + 3 > 0) &&\n    (23 * 4 > 10 * 6)\n```\n\nIf long line should be split in `Elvis Operator` (?:), it`s done like this\n\n**Invalid example:**\n```kotlin\nval value = first ?: second\n```\n**Valid example:**\n```kotlin\nval value = first\n    ?: second\n```\n\nIf long line in `Dot Qualified Expression` or `Safe Access Expression`, it`s done like this:\n\n**Invalid example:**\n```kotlin\nval value = This.Is.Very.Long.Dot.Qualified.Expression\n```\n**Valid example:**\n```kotlin\nval value = This.Is.Very.Long\n    .Dot.Qualified.Expression\n```\n\n**Invalid example:**\n```kotlin\nval value = This.Is?.Very?.Long?.Safe?.Access?.Expression\n```\n**Valid example:**\n```kotlin\nval value = This.Is?.Very?.Long\n    ?.Safe?.Access?.Expression\n```\n\nif `value arguments list` is too long, it also should be split:\n\n**Invalid example:**\n```kotlin\nval result1 = ManyParamInFunction(firstArgument, secondArgument, thirdArgument, fourthArgument, fifthArguments)\n```\n**Valid example:**\n```kotlin\nval result1 = ManyParamInFunction(firstArgument,\n secondArgument, thirdArgument, fourthArgument,\n fifthArguments)\n```\n\nIf `annotation` is too long, it also should be split:\n\n**Invalid example:**\n```kotlin\n@Query(value = \"select * from table where age = 10\", nativeQuery = true)\nfun foo() {}\n```\n**Valid example:**\n```kotlin\n@Query(\n    value = \"select * from table where age = 10\",\n    nativeQuery = true)\nfun foo() {}\n```\n\nLong one line `function` should be split:\n\n**Invalid example:**\n```kotlin\nfun foo() = goo().write(\"TooLong\")\n```\n**Valid example:**\n```kotlin\nfun foo() =\n    goo().write(\"TooLong\")\n```\n\nLong `binary expression` should be split into priorities: \\\n1. Logic Binary Expression (**&&**  **||**) \\\n2. Comparison Binary Expression (**>** **<** **==** **>=** **<=** **!=**) \\\n3. Other types (Arithmetical and Bit operation) (**+** **-** * **/** **%** **>>** **<<** **/*=** **+=** **-=** **/=** **%=** **++** **--** **!** **in** **!in** etc)\n\n**Invalid example:**\n```kotlin\nif (( x >  100) || y < 100 && !isFoo()) {}\n```\n\n**Valid example:**\n```kotlin\nif (( x >  100) ||\n    y < 100 && !isFoo()) {}\n```\n\n`String template` also can be split in white space in string text\n\n**Invalid example:**\n```kotlin\nval nameString = \"This is very long string template\"\n```\n\n**Valid example:**\n```kotlin\nval nameString = \"This is very long\" +\n        \" string template\"\n```\n\nLong `Lambda argument` should be split:\n\n**Invalid example:**\n```kotlin\nval variable = a?.filter { it.elementType == true } ?: null\n```\n\n**Valid example:**\n```kotlin\nval variable = a?.filter {\n    it.elementType == true\n} ?: null\n```\n\nLong one line `When Entry` should be split:\n\n**Invalid example:**\n```kotlin\nwhen(elem) {\n    true -> long.argument.whenEntry\n}\n```\n**Valid example:**\n```kotlin\nwhen(elem) {\n    true -> {\n        long.argument.whenEntry\n    }\n}\n```\n\nIf the examples above do not fit, but the line needs to be split and this in `property`, this is fixed like thisЖ\n\n**Invalid example:**\n```kotlin\nval element = veryLongNameFunction(firstParam)\n```\n**Valid example:**\n```kotlin\nval element =\n    varyLongNameFunction(firstParam)\n```\n\n`Eol comment` also can be split, but it depends on comment location.\nIf this comment is on the same line with code it should be on line before:\n\n**Invalid example:**\n```kotlin\nfun foo() {\n    val name = \"Nick\" // this comment is too long\n}\n```\n**Valid example:**\n```kotlin\nfun foo() {\n    // this comment is too long\n    val name = \"Nick\"\n}\n```\n\nBut if this comment is on new line - it should be split to several lines:\n\n**Invalid example:**\n```kotlin\n// This comment is too long. It should be on two lines.\nfun foo() {}\n```\n\n**Valid example:**\n```kotlin\n// This comment is too long.\n// It should be on two lines.\nfun foo() {}\n```\n\nThe international code style prohibits `non-Latin` (`non-ASCII`) symbols. (See [Identifiers](#r1.1.1)) However, if you still intend on using them, follow\nthe following convention:\n\n- One wide character occupies the width of two narrow characters.\n  The \"wide\" and \"narrow\" parts of a character are defined by its [east Asian width Unicode attribute](https://unicode.org/reports/tr11/).\n  Typically, narrow characters are also called \"half-width\" characters.\n  All characters in the ASCII character set include letters (such as `a, A`), numbers (such as `0, 3`), and punctuation spaces (such as `,` , `{`), all of which are narrow characters.\n  Wide characters are also called \"full-width\" characters. Chinese characters (such as `中, 文`), Chinese punctuation (`，` , `；` ), full-width letters and numbers (such as `Ａ、３`) are \"full-width\" characters.\n  Each one of these characters represents two narrow characters.\n\n- Any line that exceeds this limit (`120 narrow symbols`) should be wrapped, as described in the [Newline section](#c3.5).\n\n**Exceptions:**\n\n1.\tThe long URL or long JSON method reference in KDoc.\n2.\tThe `package` and `import` statements.\n3.\tThe command line in the comment, enabling it to be cut and pasted into the shell for use.\n\n<!-- =============================================================================== -->\n### <a name=\"c3.6\"></a> 3.6 Line breaks (newlines)\nThis section contains the rules and recommendations on using line breaks.\n#### <a name=\"r3.6.1\"></a> 3.6.1 Each line can have a maximum of one statement\nEach line can have a maximum of one code statement. This recommendation prohibits the use of code with `;` because it decreases code visibility.\n\n**Invalid example:**\n```kotlin\nval a = \"\"; val b = \"\"\n```\n\n**Valid example:**\n```kotlin\nval a = \"\"\nval b = \"\"\n```\n\n#### <a name=\"r3.6.2\"></a> 3.6.2 Rules for line-breaking\n\n1) Unlike Java, Kotlin allows you not to put a semicolon (`;`) after each statement separated by a newline character.\n   There should be no redundant semicolon at the end of the lines.\n\nWhen a newline character is needed to split the line, it should be placed after such operators as `&&`/`||`/`+`/etc. and all infix functions (for example, `xor`).\nHowever, the newline character should be placed before operators such as `.`, `?.`, `?:`, and `::`.\n\nNote that all comparison operators, such as `==`, `>`, `<`, should not be split.\n\n**Invalid example**:\n```kotlin\n     if (node !=\n             null && test != null) {}\n```\n\n**Valid example**:\n```kotlin\n         if (node != null &&\n                 test != null) {\n         }\n```\n\n**Note:** You need to follow the functional style, meaning each function call in a chain with `.` should start at a new line if the chain of functions contains more than one call:\n```kotlin\n  val value = otherValue!!\n          .map { x -> x }\n          .filter {\n              val a = true\n              true\n          }\n          .size\n```\n**Note:** The parser prohibits the separation of the `!!` operator from the value it is checking.\n\n**Exception**: If a functional chain is used inside the branches of a ternary operator, it does not need to be split with newlines.\n\n**Valid example**:\n```kotlin\nif (condition) list.map { foo(it) }.filter { bar(it) } else list.drop(1)\n```\n\n**Note:** If dot qualified expression is inside condition or passed as an argument - it should be replaced with new variable.\n\n**Invalid example**:\n```kotlin\n if (node.treeParent.treeParent?.treeParent.findChildByType(IDENTIFIER) != null) {}\n```\n\n**Valid example**:\n```kotlin\n        val grandIdentifier = node\n            .treeParent\n            .treeParent\n            ?.treeParent\n            .findChildByType(IDENTIFIER)\n        if (grandIdentifier != null) {}\n```\n**Second valid example**:\n```kotlin\n        val grandIdentifier = node.treeParent\n            .treeParent\n            ?.treeParent\n            .findChildByType(IDENTIFIER)\n        if (grandIdentifier != null) {}\n```\n\n2)\tNewlines should be placed after the assignment operator (`=`).\n3)\tIn function or class declarations, the name of a function or constructor should not be split by a newline from the opening brace `(`.\n      A brace should be placed immediately after the name without any spaces in declarations or at call sites.\n4)\tNewlines should be placed right after the comma (`,`).\n5)\tIf a lambda statement contains more than one line in its body, a newline should be placed after an arrow if the lambda statement has explicit parameters.\n      If it uses an implicit parameter (`it`), the newline character should be placed after the opening brace (`{`).\n      The following examples illustrate this rule:\n\n\n**Invalid example:**\n```kotlin\n    value.map { name -> foo()\n        bar()\n    }\n```\n\n**Valid example:**\n```kotlin\nvalue.map { name ->\n    foo()\n    bar()\n}\n\nval someValue = { node:String -> node }\n```\n\n6) When the function contains only a single expression, it can be written as [expression function](https://kotlinlang.org/docs/reference/functions.html#single-expression-functions).\n   The below example shows the style that should not be used.\n\nInstead of:\n```kotlin\noverride fun toString(): String { return \"hi\" }\n```\nuse:\n```kotlin\noverride fun toString() = \"hi\"\n```\n\n7)  If an argument list in a function declaration (including constructors) or function call contains more than two arguments, these arguments should be split by newlines in the following style.\n\n**Valid example:**\n ```kotlin\nclass Foo(val a: String,\n          b: String,\n          val c: String) {\n}\n\nfun foo(\n        a: String,\n        b: String,\n        c: String\n) {\n\n}\n ```\n\nIf and only if the first parameter is on the same line as an opening parenthesis, all parameters can be horizontally aligned by the first parameter.\nOtherwise, there should be a line break after an opening parenthesis.\n\nKotlin 1.4 introduced a trailing comma as an optional feature, so it is generally recommended to place all parameters on a separate line\nand append [trailing comma](https://kotlinlang.org/docs/reference/whatsnew14.html#trailing-comma).\nIt makes the resolving of merge conflicts easier.\n\n**Valid example:**\n ```kotlin\nfun foo(\n        a: String,\n        b: String,\n) {\n\n}\n ```\n\nsame should be done for function calls/constructor arguments/e.t.c\n\nKotlin supports trailing commas in the following cases:\n\nEnumerations\nValue arguments\nClass properties and parameters\nFunction value parameters\nParameters with optional type (including setters)\nIndexing suffix\nLambda parameters\nwhen entry\nCollection literals (in annotations)\nType arguments\nType parameters\nDestructuring declarations\n\n8) If the supertype list has more than two elements, they should be separated by newlines.\n\n**Valid example:**\n```kotlin\nclass MyFavouriteVeryLongClassHolder :\n    MyLongHolder<MyFavouriteVeryLongClass>(),\n    SomeOtherInterface,\n    AndAnotherOne { }\n```\n\n<!-- =============================================================================== -->\n### <a name=\"c3.7\"></a> 3.7 Using blank lines\n\nReduce unnecessary blank lines and maintain a compact code size. By reducing unnecessary blank lines, you can display more code on one screen, which improves code readability.\n- Blank lines should separate content based on relevance and should be placed between groups of fields, constructors, methods, nested classes, `init` blocks, and objects (see [3.1.2](#r3.1.2)).\n- Do not use more than one line inside methods, type definitions, and initialization expressions.\n- Generally, do not use more than two consecutive blank lines in a row.\n- Do not put newlines in the beginning or end of code blocks with curly braces.\n\n**Valid example:**\n```kotlin\nfun baz() {\n\n    doSomething()  // No need to add blank lines at the beginning and end of the code block\n    // ...\n\n}\n```\n\n<!-- =============================================================================== -->\n### <a name=\"c3.8\"></a> 3.8 Horizontal space\nThis section describes general rules and recommendations for using spaces in the code.\n#### <a name=\"r3.8.1\"></a> 3.8.1: Usage of whitespace for code separation\n\nFollow the recommendations below for using space to separate keywords:\n\n**Note:** These recommendations are for cases where symbols are located on the same line. However, in some cases, a line break could be used instead of a space.\n\n1.  Separate keywords (such as `if`, `when`, `for`) from the opening parenthesis with single whitespace.\n    The only exception is the `constructor` keyword, which should not be separated from the opening parenthesis.\n\n2.  Separate keywords like `else` or `try` from the opening brace (`{`) with single whitespace.\n    If `else` is used in a ternary-style statement without braces, there should be a single space between `else` and the statement after: `if (condition) foo() else bar()`\n\n3.  Use a **single** whitespace before all opening braces (`{`). The only exception is the passing of a lambda as a parameter inside parentheses:\n ```kotlin\n     private fun foo(a: (Int) -> Int, b: Int) {}\n     foo({x: Int -> x}, 5) // no space before '{'\n ```\n\n4.  Single whitespace should be placed on both sides of binary operators. This also applies to operator-like symbols.\n    For example:\n\n- A colon in generic structures with the `where` keyword:  `where T : Type`\n- Arrow in lambdas: `(str: String) -> str.length()`\n\n**Exceptions:**\n\n- Two colons (`::`) are written without spaces:\\\n  `Object::toString`\n- The dot separator (`.`) that stays on the same line with an object name:\\\n  `object.toString()`\n- Safe access modifiers `?.` and `!!` that stay on the same line with an object name:\\\n  `object?.toString()`\n- Operator `..` for creating ranges:\\\n  `1..100`\n\n5.  Use spaces after (`,`), (`:`), and (`;`), except when the symbol is at the end of the line.\n    However, note that this code style prohibits the use of (`;`) in the middle of a line ([see 3.3.2](#r3.2.2)).\n    There should be no whitespaces at the end of a line.\n    The only scenario where there should be no space after a colon is when the colon is used in the annotation to specify a use-site target (for example, `@param:JsonProperty`).\n    There should be no spaces before `,` , `:` and `;`.\n\n    **Exceptions** for spaces and colons:\n\n    - When `:` is used to separate a type and a supertype, including an anonymous object (after object keyword)\n    - When delegating to a superclass constructor or different constructor of the same class\n\n**Valid example:**\n```kotlin\n  abstract class Foo<out T : Any> : IFoo { }\n\n  class FooImpl : Foo() {\n      constructor(x: String) : this(x) { /*...*/ }\n\n      val x = object : IFoo { /*...*/ }\n  }\n```\n\n6. There should be *only one space* between the identifier and its type: `list: List<String>`\n   If the type is nullable, there should be no space before `?`.\n\n7. When using `[]` operator (`get/set`) there should be **no** spaces between identifier and `[` : `someList[0]`.\n\n8. There should be no space between a method or constructor name (both at declaration and at call site) and a parenthesis:\n   `foo() {}`. Note that this sub-rule is related only to spaces; the rules for whitespaces are described in [see 3.6.2](#r3.6.2).\n   This rule does not prohibit, for example, the following code:\n```kotlin\nfun foo\n(\n    a: String\n)\n```\n\n9. Never put a space after `(`, `[`, `<` (when used as a bracket in templates) or before `)`, `]`, `>` (when used as a bracket in templates).\n\n10. There should be no spaces between a prefix/postfix operator (like `!!` or `++`) and its operand.\n\n#### <a name=\"r3.8.2\"></a> 3.8.2: No spaces for horizontal alignment\n\n*Horizontal alignment* refers to aligning code blocks by adding space to the code. Horizontal alignment should not be used because:\n\n- When modifying code, it takes much time for new developers to format, support, and fix alignment issues.\n- Long identifier names will break the alignment and lead to less presentable code.\n- There are more disadvantages than advantages in alignment. To reduce maintenance costs, misalignment (???) is the best choice.\n\nRecommendation: Alignment only looks suitable for `enum class`, where it can be used in table format to improve code readability:\n```kotlin\nenum class Warnings(private val id: Int, private val canBeAutoCorrected: Boolean, private val warn: String) : Rule {\n    PACKAGE_NAME_MISSING         (1, true,  \"no package name declared in a file\"),\n    PACKAGE_NAME_INCORRECT_CASE  (2, true,  \"package name should be completely in a lower case\"),\n    PACKAGE_NAME_INCORRECT_PREFIX(3, false, \"package name should start from the company's domain\")\n    ;\n}\n```\n\n**Valid example:**\n ```kotlin\n private val nr: Int // no alignment, but looks fine\n private var color: Color // no alignment\n ```\n\n**Invalid example**:\n ```kotlin\n private val    nr: Int    // aligned comment with extra spaces\n private val color: Color  // alignment for a comment and alignment for identifier name\n ```\n\n<!-- =============================================================================== -->\n### <a name=\"c3.9\"></a> 3.9 Enumerations\nEnum values are separated by a comma and line break, with ';' placed on the new line.\n\n1) The comma and line break characters separate enum values. Put `;` on the new line:\n```kotlin\nenum class Warnings {\n    A,\n    B,\n    C,\n    ;\n}\n```\n\nThis will help to resolve conflicts and reduce the number of conflicts during merging pull requests.\nAlso, use [trailing comma](https://kotlinlang.org/docs/reference/whatsnew14.html#trailing-comma).\n\n2) If the enum is simple (no properties, methods, and comments inside), you can declare it in a single line:\n```kotlin\nenum class Suit { CLUBS, HEARTS, SPADES, DIAMONDS }\n```\n\n3) Enum classes take preference (if it is possible to use it). For example, instead of two boolean properties:\n\n```kotlin\nval isCelsius = true\nval isFahrenheit = false\n```\n\nuse enum class:\n\n```kotlin\nenum class TemperatureScale { CELSIUS, FAHRENHEIT }\n```\n\n- The variable value only changes within a fixed range and is defined with the enum type.\n- Avoid comparison with magic numbers of `-1, 0, and 1`; use enums instead.\n\n```kotlin\nenum class ComparisonResult {\n    ORDERED_ASCENDING,\n    ORDERED_SAME,\n    ORDERED_DESCENDING,\n    ;\n}\n```\n\n<!-- =============================================================================== -->\n### <a name=\"c3.10\"></a> 3.10 Variable declaration\nThis section describes rules for the declaration of variables.\n#### <a name=\"r3.10.1\"></a> 3.10.1 Declare one variable per line\n\nEach property or variable must be declared on a separate line.\n\n**Invalid example**:\n```kotlin\nval n1: Int; val n2: Int\n```\n\n#### <a name=\"r3.10.2\"></a> 3.10.2 Variables should be declared near the line where they are first used\nDeclare local variables close to the point where they are first used to minimize their scope. This will also increase the readability of the code.\nLocal variables are usually initialized during their declaration or immediately after.\nThe member fields of the class should be declared collectively (see [Rule 3.1.2](#r3.1.2) for details on the class structure).\n\n<!-- =============================================================================== -->\n### <a name=\"c3.11\"></a> 3.11 'When' expression\n\nThe `when` statement must have an 'else' branch unless the condition variable is enumerated or a sealed type.\nEach `when` statement should contain an `else` statement group, even if it does not contain any code.\n\n**Exception:** If 'when' statement of the `enum or sealed` type contains all enum values, there is no need to have an \"else\" branch.\nThe compiler can issue a warning when it is missing.\n\n<!-- =============================================================================== -->\n### <a name=\"c3.12\"></a> 3.12 Annotations\n\nEach annotation applied to a class, method or constructor should be placed on its own line. Consider the following examples:\n1. Annotations applied to the class, method or constructor are placed on separate lines (one annotation per line).\n\n**Valid example**:\n```kotlin\n@MustBeDocumented\n@CustomAnnotation\nfun getNameIfPresent() { /* ... */ }\n```\n\n2. A single annotation should be on the same line as the code it is annotating.\n\n**Valid example**:\n```kotlin\n@CustomAnnotation class Foo {}\n```\n\n3. Multiple annotations applied to a field or property can appear on the same line as the corresponding field.\n\n**Valid example**:\n```kotlin\n@MustBeDocumented @CustomAnnotation val loader: DataLoader\n```\n\n<!-- =============================================================================== -->\n### <a name=\"c3.13\"></a> 3.13 Block comments\n\nBlock comments should be placed at the same indentation level as the surrounding code. See examples below.\n\n**Valid example**:\n\n ```kotlin\nclass SomeClass {\n     /*\n      * This is\n      * okay\n      */\n      fun foo() {}\n}\n ```\n\n**Note**: Use `/*...*/` block comments to enable automatic formatting by IDEs.\n\n<!-- =============================================================================== -->\n### <a name=\"c3.14\"></a> 3.14 Modifiers and constant values\nThis section contains recommendations regarding modifiers and constant values.\n#### <a name=\"r3.14.1\"></a> 3.14.1 Declaration with multiple modifiers\nIf a declaration has multiple modifiers, always follow the proper sequence.\n**Valid sequence:**\n\n```kotlin\npublic / internal / protected / private\nexpect / actual\nfinal / open / abstract / sealed / const\nexternal\noverride\nlateinit\ntailrec\ncrossinline\nvararg\nsuspend\ninner\nout\nenum / annotation\ncompanion\ninline / noinline\nreified\ninfix\noperator\ndata\n```\n\n#### <a name=\"r3.14.2\"></a> 3.14.2: Separate long numerical values with an underscore\nAn underscore character should separate long numerical values.\n**Note:** Using underscores simplifies reading and helps to find errors in numeric constants.\n```kotlin\nval oneMillion = 1_000_000\nval creditCardNumber = 1234_5678_9012_3456L\nval socialSecurityNumber = 999_99_9999L\nval hexBytes = 0xFF_EC_DE_5E\nval bytes = 0b11010010_01101001_10010100_10010010\n```\n#### <a name=\"r3.14.3\"></a> 3.14.3: Magic number\nPrefer defining constants with clear names describing what the magic number means.\n**Valid example**:\n```kotlin\nclass Person() {\n    fun isAdult(age: Int): Boolean = age >= majority\n\n    companion object {\n        private const val majority = 18\n    }\n}\n```\n**Invalid example**:\n```kotlin\nclass Person() {\n    fun isAdult(age: Int): Boolean = age >= 18\n}\n```\n\n<!-- =============================================================================== -->\n### <a name=\"c3.15\"></a> 3.15 Strings\nThis section describes the general rules of using strings.\n\n#### <a name=\"r3.15.1\"></a> 3.15.1 Concatenation of Strings\nString concatenation is prohibited if the string can fit on one line. Use raw strings and string templates instead. Kotlin has significantly improved the use of Strings:\n[String templates](https://kotlinlang.org/docs/reference/basic-types.html#string-templates), [Raw strings](https://kotlinlang.org/docs/reference/basic-types.html#string-literals).\nTherefore, compared to using explicit concatenation, code looks much better when proper Kotlin strings are used for short lines, and you do not need to split them with newline characters.\n\n**Invalid example**:\n```kotlin\nval myStr = \"Super string\"\nval value = myStr + \" concatenated\"\n```\n\n**Valid example**:\n```kotlin\nval myStr = \"Super string\"\nval value = \"$myStr concatenated\"\n```\n\n#### <a name=\"r3.15.2\"></a> 3.15.2 String template format\n**Redundant curly braces in string templates**\n\nIf there is only one variable in a string template, there is no need to use such a template. Use this variable directly.\n**Invalid example**:\n```kotlin\nval someString = \"${myArgument} ${myArgument.foo()}\"\n```\n\n**Valid example**:\n```kotlin\nval someString = \"$myArgument ${myArgument.foo()}\"\n```\n\n**Redundant string template**\n\nIn case a string template contains only one variable - there is no need to use the string template. Use this variable directly.\n\n**Invalid example**:\n```kotlin\nval someString = \"$myArgument\"\n```\n\n**Valid example**:\n```kotlin\nval someString = myArgument\n```\n\n<!-- =============================================================================== -->\n### <a name=\"c3.16\"></a> 3.16 Conditional Statements\nThis section describes the general rules related to the сonditional statements.\n\n#### <a name=\"r3.16.1\"></a> 3.16.1 Collapsing redundant nested if-statements\nThe nested if-statements, when possible, should be collapsed into a single one\nby concatenating their conditions with the infix operator &&.\n\nThis improves the readability by reducing the number of the nested language constructs.\n\n#### Simple collapse\n\n**Invalid example**:\n```kotlin\nif (cond1) {\n    if (cond2) {\n        doSomething()\n    }\n}\n```\n\n**Valid example**:\n```kotlin\nif (cond1 && cond2) {\n    doSomething()\n}\n```\n\n#### Compound conditions\n\n**Invalid example**:\n```kotlin\nif (cond1) {\n    if (cond2 || cond3) {\n        doSomething()\n    }\n}\n```\n\n**Valid example**:\n```kotlin\nif (cond1 && (cond2 || cond3)) {\n    doSomething()\n}\n```\n#### <a name=\"r3.16.2\"></a> 3.16.2 Too complex conditions\nToo complex conditions should be simplified according to boolean algebra rules, if it is possible.\nThe following rules are considered when simplifying an expression:\n* boolean literals are removed (e.g. `foo() || false` -> `foo()`)\n* double negation is removed (e.g. `!(!a)` -> `a`)\n* expression with the same variable are simplified (e.g. `a && b && a` -> `a && b`)\n* remove expression from disjunction, if they are subset of other expression (e.g. `a || (a && b)` -> `a`)\n* remove expression from conjunction, if they are more broad than other expression (e.g. `a && (a || b)` -> `a`)\n* de Morgan's rule (negation is moved inside parentheses, i.e. `!(a || b)` -> `!a && !b`)\n\n**Valid example**\n```kotlin\nif (condition1 && condition2) {\n    foo()\n}\n```\n\n**Invalid example**\n```kotlin\nif (condition1 && condition2 && condition1) {\n    foo()\n}\n```\n# <a name=\"c4\"></a> 4. Variables and types\nThis section is dedicated to the rules and recommendations for using variables and types in your code.\n<!-- =============================================================================== -->\n### <a name=\"c4.1\"></a> 4.1 Variables\nThe rules of using variables are explained in the below topics.\n#### <a name=\"r4.1.1\"></a> 4.1.1 Do not use Float and Double types when accurate calculations are needed\nFloating-point numbers provide a good approximation over a wide range of values, but they cannot produce accurate results in some cases.\nBinary floating-point numbers are unsuitable for precise calculations because it is impossible to represent 0.1 or any other negative power of 10 in a `binary representation` with a finite length.\n\nThe following code example seems to be obvious:\n```kotlin\n    val myValue = 2.0 - 1.1\n    println(myValue)\n```\n\nHowever, it will print the following value: `0.8999999999999999`\n\nTherefore, for precise calculations (for example, in finance or exact sciences), using such types as `Int`, `Long`, `BigDecimal`are recommended.\nThe `BigDecimal` type should serve as a good choice.\n\n**Invalid example**:\nFloat values containing more than six or seven decimal numbers will be rounded.\n ```kotlin\n val eFloat = 2.7182818284f // Float, will be rounded to 2.7182817\n ```\n\n**Valid example**: (when precise calculations are needed):\n ```kotlin\n    val income = BigDecimal(\"2.0\")\n    val expense = BigDecimal(\"1.1\")\n    println(income.subtract(expense)) // you will obtain 0.9 here\n ```\n\n#### <a name=\"r4.1.2\"></a> 4.1.2: Comparing numeric float type values\nNumeric float type values should not be directly compared with the equality operator (==) or other methods, such as `compareTo()` and `equals()`. Since floating-point numbers involve precision problems in computer representation, it is better to use `BigDecimal` as recommended in [Rule 4.1.1](#r4.1.1) to make accurate computations and comparisons. The following code describes these problems.\n\n**Invalid example**:\n ```kotlin\nval f1 = 1.0f - 0.9f\nval f2 = 0.9f - 0.8f\nif (f1 == f2) {\n    println(\"Expected to enter here\")\n} else {\n    println(\"But this block will be reached\")\n}\n\nval flt1 = f1;\nval flt2 = f2;\nif (flt1.equals(flt2)) {\n    println(\"Expected to enter here\")\n} else {\n    println(\"But this block will be reached\")\n}\n ```\n\n**Valid example**:\n\n```kotlin\nval foo = 1.03f\nval bar = 0.42f\nif (abs(foo - bar) > 1e-6f) {\n    println(\"Ok\")\n} else {\n    println(\"Not\")\n}\n```\n\n#### <a name=\"r4.1.3\"></a> 4.1.3 Try to use 'val' instead of 'var' for variable declaration [SAY_NO_TO_VAR]\n\nVariables with the `val` modifier are immutable (read-only).\nUsing `val` variables instead of `var` variables increases code robustness and readability.\nThis is because `var` variables can be reassigned several times in the business logic.\nHowever, in some scenarios with loops or accumulators, only `var`s are permitted.\n\n<!-- =============================================================================== -->\n### <a name=\"c4.2\"></a> 4.2 Types\nThis section provides recommendations for using types.\n#### <a name=\"r4.2.1\"></a> 4.2.1: Use Contracts and smart cast as much as possible\n\nThe Kotlin compiler has introduced [Smart Casts](https://kotlinlang.org/docs/reference/typecasts.html#smart-casts) that help reduce the size of code.\n\n**Invalid example**:\n```kotlin\n    if (x is String) {\n        print((x as String).length) // x was already automatically cast to String - no need to use 'as' keyword here\n    }\n```\n\n**Valid example**:\n```kotlin\n    if (x is String) {\n        print(x.length) // x was already automatically cast to String - no need to use 'as' keyword here\n    }\n```\n\nAlso, Kotlin 1.3 introduced [Contracts](https://kotlinlang.org/docs/reference/whatsnew13.html#contracts) that provide enhanced logic for smart-cast.\nContracts are used and are very stable in `stdlib`, for example:\n\n\n```kotlin\nfun bar(x: String?) {\n    if (!x.isNullOrEmpty()) {\n        println(\"length of '$x' is ${x.length}\") // smartcasted to not-null\n    }\n}\n```\n\nSmart cast and contracts are a better choice because they reduce boilerplate code and features forced type conversion.\n\n**Invalid example**:\n```kotlin\nfun String?.isNotNull(): Boolean = this != null\n\nfun foo(s: String?) {\n    if (s.isNotNull()) s!!.length // No smartcast here and !! operator is used\n}\n```\n\n**Valid example**:\n```kotlin\nfun foo(s: String?) {\n    if (s.isNotNull()) s.length // We have used a method with contract from stdlib that helped compiler to execute smart cast\n}\n```\n\n#### <a name=\"r4.2.2\"></a> 4.2.2: Try to use type alias to represent types making code more readable\n\nType aliases provide alternative names for existing types.\nIf the type name is too long, you can replace it with a shorter name, which helps to shorten long generic types.\nFor example, code looks much more readable if you introduce a `typealias` instead of a long chain of nested generic types.\nWe recommend using a `typealias` if the type contains **more than two** nested generic types and is longer than **25 chars**.\n\n**Invalid example**:\n```kotlin\nval b: MutableMap<String, MutableList<String>>\n```\n\n**Valid example**:\n```kotlin\ntypealias FileTable = MutableMap<String, MutableList<String>>\nval b: FileTable\n```\n\nYou can also provide additional aliases for function (lambda-like) types:\n```kotlin\ntypealias MyHandler = (Int, String, Any) -> Unit\n\ntypealias Predicate<T> = (T) -> Boolean\n```\n\n<!-- =============================================================================== -->\n### <a name=\"c4.3\"></a> 4.3 Null safety and variable declarations\nKotlin is declared as a null-safe programming language. However, to achieve compatibility with Java, it still supports nullable types.\n\n#### <a name=\"r4.3.1\"></a> 4.3.1: Avoid declaring variables with nullable types, especially from Kotlin stdlib\nTo avoid `NullPointerException` and help the compiler prevent Null Pointer Exceptions, avoid using nullable types (with `?` symbol).\n\n**Invalid example**:\n```kotlin\nval a: Int? = 0\n```\n\n**Valid example**:\n```kotlin\nval a: Int = 0\n```\n\nNevertheless, when using Java libraries extensively, you have to use nullable types and enrich the code with `!!` and `?` symbols.\nAvoid using nullable types for Kotlin stdlib (declared in [official documentation](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.collections/)).\nTry to use initializers for empty collections. For example, if you want to initialize a list instead of `null`, use `emptyList()`.\n\n**Invalid example**:\n```kotlin\nval a: List<Int>? = null\n```\n\n**Valid example**:\n```kotlin\nval a: List<Int> = emptyList()\n```\n\n#### <a name=\"r4.3.2\"></a> 4.3.2: Variables of generic types should have an explicit type declaration\nLike in Java, classes in Kotlin may have type parameters. To create an instance of such a class, we typically need to provide type arguments:\n\n```kotlin\nval myVariable: Map<Int, String> = emptyMap<Int, String>()\n```\n\nHowever, the compiler can inherit type parameters from the r-value (value assigned to a variable). Therefore, it will not force users to declare the type explicitly.\nThese declarations are not recommended because programmers would need to find the return value and understand the variable type by looking at the method.\n\n**Invalid example**:\n```kotlin\nval myVariable = emptyMap<Int, String>()\n```\n\n**Valid example**:\n```kotlin\nval myVariable: Map<Int, String> = emptyMap()\n```\n\n#### <a name=\"r4.3.3\"></a> 4.3.3 Null-safety\n\nTry to avoid explicit null checks (explicit comparison with `null`)\nKotlin is declared as [Null-safe](https://kotlinlang.org/docs/reference/null-safety.html) language.\nHowever, Kotlin architects wanted Kotlin to be fully compatible with Java; that's why the `null` keyword was also introduced in Kotlin.\n\nThere are several code-structures that can be used in Kotlin to avoid null-checks. For example: `?:`,  `.let {}`, `.also {}`, e.t.c\n\n**Invalid example:**\n```kotlin\n// example 1\nvar myVar: Int? = null\nif (myVar == null) {\n    println(\"null\")\n    return\n}\n\n// example 2\nif (myVar != null) {\n    println(\"not null\")\n    return\n}\n\n// example 3\nval anotherVal = if (myVar != null) {\n                     println(\"not null\")\n                     1\n                 } else {\n                     2\n                 }\n// example 4\nif (myVar == null) {\n    println(\"null\")\n} else {\n    println(\"not null\")\n}\n```\n\n**Valid example:**\n```kotlin\n// example 1\nvar myVar: Int? = null\nmyVar?: run {\n    println(\"null\")\n    return\n}\n\n// example 2\nmyVar?.let {\n    println(\"not null\")\n    return\n}\n\n// example 3\nval anotherVal = myVar?.also {\n                     println(\"not null\")\n                     1\n                 } ?: 2\n\n// example 4\nmyVar?.let {\n    println(\"not null\")\n} ?: run { println(\"null\") }\n```\n\n**Exceptions:**\n\nIn the case of complex expressions, such as multiple `else-if` structures or long conditional statements, there is common sense to use explicit comparison with `null`.\n\n**Valid examples:**\n\n```kotlin\nif (myVar != null) {\n    println(\"not null\")\n} else if (anotherCondition) {\n    println(\"Other condition\")\n}\n```\n\n```kotlin\nif (myVar == null || otherValue == 5 && isValid) {}\n```\n\nPlease also note, that instead of using `require(a != null)` with a not null check - you should use a special Kotlin function called `requireNotNull(a)`.\n\n# <a name=\"c5\"></a> 5. Functions\nThis section describes the rules of using functions in your code.\n<!-- =============================================================================== -->\n### <a name=\"c5.1\"></a> 5.1 Function design\nDevelopers can write clean code by gaining knowledge of how to build design patterns and avoid code smells.\nYou should utilize this approach, along with functional style, when writing Kotlin code.\nThe concepts behind functional style are as follows:\nFunctions are the smallest unit of combinable and reusable code.\nThey should have clean logic, **high cohesion**, and **low coupling** to organize the code effectively.\nThe code in functions should be simple and not conceal the author's original intentions.\n\nAdditionally, it should have a clean abstraction, and control statements should be used straightforwardly.\nThe side effects (code that does not affect a function's return value but affects global/object instance variables) should not be used for state changes of an object.\nThe only exceptions to this are state machines.\n\nKotlin is [designed](https://www.slideshare.net/abreslav/whos-more-functional-kotlin-groovy-scala-or-java) to support and encourage functional programming, featuring the corresponding built-in mechanisms.\nAlso, it supports standard collections and sequences feature methods that enable functional programming (for example, `apply`, `with`, `let`, and `run`), Kotlin Higher-Order functions, function types, lambdas, and default function arguments.\nAs [previously discussed](#r4.1.3), Kotlin supports and encourages the use of immutable types, which in turn motivates programmers to write pure functions that avoid side effects and have a corresponding output for specific input.\nThe pipeline data flow for the pure function comprises a functional paradigm. It is easy to implement concurrent programming when you have chains of function calls, where each step features the following characteristics:\n1.\tSimplicity\n2.\tVerifiability\n3.\tTestability\n4.\tReplaceability\n5.\tPluggability\n6.\tExtensibility\n7.\tImmutable results\n\nThere can be only one side effect in this data stream, which can be placed only at the end of the execution queue.\n\n#### <a name=\"r5.1.1\"></a> 5.1.1 Avoid functions that are too long\n\nThe function should be displayable on one screen and only implement one certain logic.\nIf a function is too long, it often means complex and could be split or simplified. Functions should consist of 30 lines (non-empty and non-comment) in total.\n\n**Exception:** Some functions that implement complex algorithms may exceed 30 lines due to aggregation and comprehensiveness.\nLinter warnings for such functions **can be suppressed**.\n\nEven if a long function works well, new problems or bugs may appear due to the function's complex logic once it is modified by someone else.\nTherefore, it is recommended to split such functions into several separate and shorter functions that are easier to manage.\nThis approach will enable other programmers to read and modify the code properly.\n#### <a name=\"r5.1.2\"></a> 5.1.2 Avoid deep nesting of function code blocks, limiting to four levels\n\nThe nesting depth of a function's code block is the depth of mutual inclusion between the code control blocks in the function (for example: if, for, while, and when).\nEach nesting level will increase the amount of effort needed to read the code because you need to remember the current \"stack\" (for example, entering conditional statements and loops).\n**Exception:** The nesting levels of the lambda expressions, local classes, and anonymous classes in functions are calculated based on the innermost function. The nesting levels of enclosing methods are not accumulated.\nFunctional decomposition should be implemented to avoid confusion for the developer who reads the code.\nThis will help the reader switch between contexts.\n\n#### <a name=\"r5.1.3\"></a> 5.1.3 Avoid using nested functions\nNested functions create a more complex function context, thereby confusing readers.\nWith nested functions, the visibility context may not be evident to the code reader.\n\n**Invalid example**:\n```kotlin\nfun foo() {\n    fun nested():String {\n        return \"String from nested function\"\n    }\n    println(\"Nested Output: ${nested()}\")\n}\n```\n#### <a name=\"r5.1.4\"></a> 5.1.4 Negated function calls\nDon't use negated function calls if it can be replaced with negated version of this function\n\n**Invalid example**:\n```kotlin\nfun foo() {\n    val list = listOf(1, 2, 3)\n\n    if (!list.isEmpty()) {\n        // Some cool logic\n    }\n}\n```\n\n**Valid example**:\n```kotlin\nfun foo() {\n    val list = listOf(1, 2, 3)\n\n    if (list.isNotEmpty()) {\n        // Some cool logic\n    }\n}\n```\n\n<!-- =============================================================================== -->\n### <a name=\"c5.2\"></a> 5.2 Function arguments\nThe rules for using function arguments are described in the below topics.\n#### <a name=\"r5.2.1\"></a> 5.2.1 The lambda parameter of the function should be placed at the end of the argument list\n\nWith such notation, it is easier to use curly brackets, leading to better code readability.\n\n**Valid example**:\n```kotlin\n// declaration\nfun myFoo(someArg: Int, myLambda: () -> Unit) {\n// ...\n}\n\n// usage\nmyFoo(1) {\nprintln(\"hey\")\n}\n```\n\n#### <a name=\"r5.2.2\"></a> 5.2.2 Number of function parameters should be limited to five\n\nA long argument list is a [code smell](https://en.wikipedia.org/wiki/Code_smell) that leads to less reliable code.\nIt is recommended to reduce the number of parameters. Having **more than five** parameters leads to difficulties in maintenance and conflicts merging.\nIf parameter groups appear in different functions multiple times, these parameters are closely related and can be encapsulated into a single Data Class.\nIt is recommended that you use Data Classes and Maps to unify these function arguments.\n\n#### <a name=\"r5.2.3\"></a> 5.2.3 Use default values for function arguments instead of overloading them\nIn Java, default values for function arguments are prohibited. That is why the function should be overloaded when you need to create a function with fewer arguments.\nIn Kotlin, you can use default arguments instead.\n\n**Invalid example**:\n```kotlin\nprivate fun foo(arg: Int) {\n    // ...\n}\n\nprivate fun foo() {\n    // ...\n}\n```\n\n**Valid example**:\n```kotlin\n private fun foo(arg: Int = 0) {\n     // ...\n }\n```\n#### <a name=\"r5.2.4\"></a> 5.2.4 Synchronizing code inside asynchronous code\nTry to avoid using `runBlocking` in asynchronous code\n\n**Invalid example**:\n```kotlin\nGlobalScope.async {\n    runBlocking {\n        count++\n    }\n}\n```\n#### <a name=\"r5.2.5\"></a> 5.2.5 Long lambdas should have explicit parameters\nThe lambda without parameters shouldn't be too long.\nIf a lambda is too long, it can confuse the user. Lambda without parameters should consist of 10 lines (non-empty and non-comment) in total.\n\n#### <a name=\"r5.2.6\"></a> 5.2.6 Avoid using unnecessary, custom label\nExpressions with unnecessary, custom labels generally increase complexity and worsen the maintainability of the code.\n\n**Invalid example**:\n```kotlin\nrun lab@ {\n    list.forEach {\n        return@lab\n    }\n}\n```\n\n**Valid example**:\n```kotlin\nlist.forEachIndexed { index, i ->\n    return@forEachIndexed\n}\n\nlab@ for(i: Int in q) {\n    for (j: Int in q) {\n        println(i)\n        break@lab\n    }\n}\n```\n# <a name=\"c6\"></a> 6. Classes, interfaces, and extension functions\n<!-- =============================================================================== -->\n### <a name=\"c6.1\"></a> 6.1 Classes\nThis section describes the rules of denoting classes in your code.\n#### <a name=\"r6.1.1\"></a> 6.1.1  Denoting a class with a single constructor\nWhen a class has a single constructor, it should be defined as a primary constructor in the declaration of the class. If the class contains only one explicit constructor, it should be converted to a primary constructor.\n\n**Invalid example**:\n```kotlin\nclass Test {\n    var a: Int\n    constructor(a: Int) {\n        this.a = a\n    }\n}\n```\n\n**Valid example**:\n```kotlin\nclass Test(var a: Int) {\n    // ...\n}\n\n// in case of any annotations or modifiers used on a constructor:\nclass Test private constructor(var a: Int) {\n    // ...\n}\n```\n\n#### <a name=\"r6.1.2\"></a> 6.1.2 Prefer data classes instead of classes without any functional logic\nSome people say that the data class is a code smell. However, if you need to use it (which makes your code more simple), you can utilize the Kotlin `data class`. The main purpose of this class is to hold data,\nbut also `data class` will automatically generate several useful methods:\n- equals()/hashCode() pair;\n- toString()\n- componentN() functions corresponding to the properties in their order of declaration;\n- copy() function\n\nTherefore, instead of using `normal` classes:\n\n```kotlin\nclass Test {\n    var a: Int = 0\n        get() = field\n        set(value: Int) { field = value}\n}\n\nclass Test {\n    var a: Int = 0\n    var b: Int = 0\n\n    constructor(a:Int, b: Int) {\n        this.a = a\n        this.b = b\n    }\n}\n\n// or\nclass Test(var a: Int = 0, var b: Int = 0)\n\n// or\nclass Test() {\n    var a: Int = 0\n    var b: Int = 0\n}\n```\n\n**prefer data classes:**\n```kotlin\ndata class Test1(var a: Int = 0, var b: Int = 0)\n```\n\n**Exception 1**: Note that data classes cannot be abstract, open, sealed, or inner; that is why these types of classes cannot be changed to a data class.\n\n**Exception 2**: No need to convert a class to a data class if this class extends some other class or implements an interface.\n\n#### <a name=\"r6.1.3\"></a> 6.1.3 Do not use the primary constructor if it is empty or useless\nThe primary constructor is a part of the class header; it is placed after the class name and type parameters (optional) but can be omitted if it is not used.\n\n**Invalid example**:\n```kotlin\n// simple case that does not need a primary constructor\nclass Test() {\n    var a: Int = 0\n    var b: Int = 0\n}\n\n// empty primary constructor is not needed here\n// it can be replaced with a primary contructor with one argument or removed\nclass Test() {\n    var a  = \"Property\"\n\n    init {\n        println(\"some init\")\n    }\n\n    constructor(a: String): this() {\n        this.a = a\n    }\n}\n```\n\n**Valid example**:\n```kotlin\n// the good example here is a data class; this example also shows that you should get rid of braces for the primary constructor\nclass Test {\n    var a: Int = 0\n    var b: Int = 0\n}\n```\n\n#### <a name=\"r6.1.4\"></a> 6.1.4 Do not use redundant init blocks in your class\nSeveral init blocks are redundant and generally should not be used in your class. The primary constructor cannot contain any code. That is why Kotlin has introduced `init` blocks.\nThese blocks store the code to be run during the class initialization.\nKotlin allows writing multiple initialization blocks executed in the same order as they appear in the class body.\nEven when you follow (rule 3.2)[#r3.2], this makes your code less readable as the programmer needs to keep in mind all init blocks and trace the execution of the code.\nTherefore, you should try to use a single `init` block to reduce the code's complexity. If you need to do some logging or make some calculations before the class property assignment, you can use powerful functional programming. This will reduce the possibility of the error if your `init` blocks' order is accidentally changed and\nmake the code logic more coupled. It is always enough to use one `init` block to implement your idea in Kotlin.\n\n**Invalid example**:\n```kotlin\nclass YourClass(var name: String) {\n    init {\n        println(\"First initializer block that prints ${name}\")\n    }\n\n    val property = \"Property: ${name.length}\".also(::println)\n\n    init {\n        println(\"Second initializer block that prints ${name.length}\")\n    }\n}\n```\n\n**Valid example**:\n```kotlin\nclass YourClass(var name: String) {\n    init {\n        println(\"First initializer block that prints ${name}\")\n    }\n\n    val property = \"Property: ${name.length}\".also { prop ->\n        println(prop)\n        println(\"Second initializer block that prints ${name.length}\")\n    }\n}\n```\n\nThe `init` block was not added to Kotlin to help you initialize your properties; it is needed for more complex tasks.\nTherefore if the `init` block contains only assignments of variables - move it directly to properties to be correctly initialized near the declaration.\nIn some cases, this rule can be in clash with [6.1.1](#r6.1.1), but that should not stop you.\n\n**Invalid example**:\n```kotlin\nclass A(baseUrl: String) {\n    private val customUrl: String\n    init {\n        customUrl = \"$baseUrl/myUrl\"\n    }\n}\n```\n\n**Valid example**:\n```kotlin\nclass A(baseUrl: String) {\n    private val customUrl = \"$baseUrl/myUrl\"\n}\n```\n\n#### <a name=\"r6.1.5\"></a> 6.1.5 Explicit supertype qualification\nThe explicit supertype qualification should not be used if there is no clash between called methods. This rule is applicable to both interfaces and classes.\n\n**Invalid example**:\n```kotlin\nopen class Rectangle {\n    open fun draw() { /* ... */ }\n}\n\nclass Square() : Rectangle() {\n    override fun draw() {\n        super<Rectangle>.draw() // no need in super<Rectangle> here\n    }\n}\n```\n\n#### <a name=\"r6.1.6\"></a> 6.1.6 Abstract class should have at least one abstract method\nAbstract classes are used to force a developer to implement some of its parts in their inheritors.\nWhen the abstract class has no abstract methods, it was set `abstract` incorrectly and can be converted to a regular class.\n\n**Invalid example**:\n```kotlin\nabstract class NotAbstract {\n    fun foo() {}\n\n    fun test() {}\n}\n```\n\n**Valid example**:\n```kotlin\nabstract class NotAbstract {\n    abstract fun foo()\n\n    fun test() {}\n}\n\n// OR\nclass NotAbstract {\n    fun foo() {}\n\n    fun test() {}\n}\n```\n\n\n#### <a name=\"r6.1.7\"></a> 6.1.7 When using the \"implicit backing property\" scheme, the name of real and back property should be the same\nKotlin has a mechanism of [backing properties](https://kotlinlang.org/docs/reference/properties.html#backing-properties).\nIn some cases, implicit backing is not enough and it should be done explicitly:\n```kotlin\nprivate var _table: Map<String, Int>? = null\nval table: Map<String, Int>\n    get() {\n        if (_table == null) {\n            _table = HashMap() // Type parameters are inferred\n        }\n        return _table ?: throw AssertionError(\"Set to null by another thread\")\n    }\n```\n\nIn this case, the name of the backing property (`_table`) should be the same as the name of the real property (`table`) but should have an underscore (`_`) prefix.\nIt is one of the exceptions from the [identifier names rule](#r1.2)\n\n#### <a name=\"r6.1.8\"></a> 6.1.8 Avoid using custom getters and setters\nKotlin has a perfect mechanism of [properties](https://kotlinlang.org/docs/reference/properties.html#properties-and-fields).\nKotlin compiler automatically generates `get` and `set` methods for properties and can override them.\n\n**Invalid example:**\n```kotlin\nclass A {\n    var size: Int = 0\n        set(value) {\n            println(\"Side effect\")\n            field = value\n        }\n        // user of this class does not expect calling A.size receive size * 2\n        get() = field * 2\n}\n```\n\nFrom the callee code, these methods look like access to this property: `A().isEmpty = true` for setter and `A().isEmpty` for getter.\n\nHowever, when `get` and `set` are overridden, it  isn't very clear for a developer who uses this particular class.\nThe developer expects to get the property value but receives some unknown value and some extra side-effect hidden by the custom getter/setter.\nUse extra functions instead to avoid confusion.\n\n\n\n**Valid example**:\n```kotlin\nclass A {\n    var size: Int = 0\n    fun initSize(value: Int) {\n        // some custom logic\n    }\n\n    // this will not confuse developer and he will get exactly what he expects\n    fun goodNameThatDescribesThisGetter() = this.size * 2\n}\n```\n\n**Exception:** `Private setters` are only exceptions that are not prohibited by this rule.\n\n#### <a name=\"r6.1.9\"></a> 6.1.9 Never use the name of a variable in the custom getter or setter (possible_bug)\nIf you ignored [recommendation 6.1.8](#r6.1.8), be careful with using the name of the property in your custom getter/setter\nas it can accidentally cause a recursive call and a `StackOverflow Error`. Use the `field` keyword instead.\n\n**Invalid example (very bad)**:\n```kotlin\nvar isEmpty: Boolean\n    set(value) {\n        println(\"Side effect\")\n        isEmpty = value\n    }\n    get() = isEmpty\n```\n\n#### <a name=\"r6.1.10\"></a> 6.1.10 No trivial getters and setters are allowed in the code\nIn Java, trivial getters - are the getters that are just returning the field value.\nTrivial setters - are merely setting the field with a value without any transformation.\nHowever, in Kotlin, trivial getters/setters are generated by default. There is no need to use it explicitly for all types of data structures in Kotlin.\n\n**Invalid example**:\n```kotlin\nclass A {\n    var a: Int = 0\n    get() = field\n    set(value: Int) { field = value }\n\n    //\n}\n```\n\n**Valid example**:\n```kotlin\nclass A {\n    var a: Int = 0\n    get() = field\n    set(value: Int) { field = value }\n\n    //\n}\n```\n\n#### <a name=\"r6.1.11\"></a> 6.1.11 Use 'apply' for grouping object initialization\nIn Java, before functional programming became popular, many classes from common libraries used the configuration paradigm.\nTo use these classes, you had to create an object with the constructor with 0-2 arguments and set the fields needed to run the object.\nIn Kotlin, to reduce the number of dummy code line and to group objects [`apply` extension](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/apply.html) was added:\n\n**Invalid example**:\n```kotlin\nclass HttpClient(var name: String) {\n    var url: String = \"\"\n    var port: String = \"\"\n    var timeout = 0\n\n    fun doRequest() {}\n}\n\nfun main() {\n    val httpClient = HttpClient(\"myConnection\")\n    httpClient.url = \"http://example.com\"\n    httpClient.port = \"8080\"\n    httpClient.timeout = 100\n\n    httpCLient.doRequest()\n}\n\n```\n\n**Valid example**:\n```kotlin\nclass HttpClient(var name: String) {\n    var url: String = \"\"\n    var port: String = \"\"\n    var timeout = 0\n\n    fun doRequest() {}\n}\n\nfun main() {\n    val httpClient = HttpClient(\"myConnection\")\n            .apply {\n                url = \"http://example.com\"\n                port = \"8080\"\n                timeout = 100\n            }\n    httpClient.doRequest()\n}\n```\n\n### <a name=\"r6.1.12\"></a> 6.1.12 Prefer Inline classes when a class has a single property\nIf a class has only one immutable property, then it can be converted to the inline class.\n\nSometimes it is necessary for business logic to create a wrapper around some type. However, it introduces runtime overhead due to additional heap allocations. Moreover, if the wrapped type is primitive, the performance hit is terrible, because primitive types are usually heavily optimized by the runtime, while their wrappers don't get any special treatment.\n\n**Invalid example**:\n```kotlin\nclass Password {\n    val value: String\n}\n```\n\n**Valid example**:\n```kotlin\ninline class Password(val value: String)\n```\n\n<!-- =============================================================================== -->\n### <a name=\"c6.2\"></a>6.2 Extension functions\nThis section describes the rules of using extension functions in your code.\n\n[Extension functions](https://kotlinlang.org/docs/reference/extensions.html) is a killer-feature in Kotlin.\nIt gives you a chance to extend classes that were already implemented in external libraries and helps you to make classes less heavy.\nExtension functions are resolved statically.\n\n#### <a name=\"r6.2.1\"></a> 6.2.1 Use extension functions for making logic of classes less coupled\nIt is recommended that for classes, the non-tightly coupled functions, which are rarely used in the class, should be implemented as extension functions where possible.\nThey should be implemented in the same class/file where they are used. This is a non-deterministic rule, so the code cannot be checked or fixed automatically by a static analyzer.\n\n#### <a name=\"r6.2.2\"></a> 6.2.2 No extension functions with the same name and signature if they extend base and inheritor classes (possible_bug)\nYou should avoid declaring extension functions with the same name and signature if their receivers are base and inheritor classes (possible_bug),\nas extension functions are resolved statically. There could be a situation when a developer implements two extension functions: one is for the base class and\nanother for the inheritor. This can lead to an issue when an incorrect method is used.\n\n**Invalid example**:\n```kotlin\nopen class A\nclass B: A()\n\n// two extension functions with the same signature\nfun A.foo() = \"A\"\nfun B.foo() = \"B\"\n\nfun printClassName(s: A) { println(s.foo()) }\n\n// this call will run foo() method from the base class A, but\n// programmer can expect to run foo() from the class inheritor B\nfun main() { printClassName(B()) }\n```\n\n#### <a name=\"r6.2.3\"></a> 6.2.3 Don't use extension functions for the class in the same file\nYou should not use extension functions for the class in the same file, where it is defined.\n\n**Invalid example**:\n```kotlin\nclass SomeClass {\n\n}\n\nfun SomeClass.deleteAllSpaces() {\n\n}\n```\n\n#### <a name=\"r6.2.4\"></a> 6.2.4 Use 'lastIndex' in case you need to get latest element of a collection\nYou should not use property length with operation - 1, you can change this to lastIndex\n\n**Invalid example**:\n```kotlin\nval A = \"name\"\nval B = A.length - 1\nval C = A[A.length - 1]\n```\n\n**Valid example**:\n```kotlin\nval A = \"name\"\nval B = A.lastIndex\nval C = A[A.lastIndex]\n```\n\n\n\n<!-- =============================================================================== -->\n### <a name=\"c6.3\"></a> 6.3 Interfaces\nAn `Interface` in Kotlin can contain declarations of abstract methods, as well as method implementations. What makes them different from abstract classes is that interfaces cannot store state.\nThey can have properties, but these need to be abstract or to provide accessor implementations.\n\nKotlin's interfaces can define attributes and functions.\nIn Kotlin and Java, the interface is the main presentation means of application programming interface (API) design and should take precedence over the use of (abstract) classes.\n\n<!-- =============================================================================== -->\n### <a name=\"c6.4\"></a> 6.4 Objects\nThis section describes the rules of using objects in code.\n#### <a name=\"r6.4.1\"></a> 6.4.1 Instead of using utility classes/objects, use extensions\nAvoid using utility classes/objects; use extensions instead. As described in [6.2 Extension functions](#c6.2), using extension functions is a powerful method.\nThis enables you to avoid unnecessary complexity and class/object wrapping and use top-level functions instead.\n\n**Invalid example**:\n```kotlin\nobject StringUtil {\n    fun stringInfo(myString: String): Int {\n        return myString.count{ \"something\".contains(it) }\n    }\n}\nStringUtil.stringInfo(\"myStr\")\n```\n\n**Valid example**:\n```kotlin\nfun String.stringInfo(): Int {\n    return this.count{ \"something\".contains(it) }\n}\n\n\"myStr\".stringInfo()\n```\n\n#### <a name=\"r6.4.2\"></a> 6.4.2 Objects should be used for Stateless Interfaces\nKotlin’s objects are extremely useful when you need to implement some interface from an external library that does not have any state.\nThere is no need to use classes for such structures.\n\n**Valid example**:\n```\ninterface I {\n    fun foo()\n}\n\nobject O: I {\n    override fun foo() {}\n}\n```\n### <a name=\"c6.5\"></a> 6.5 Kts Files\nThis section describes general rules for `.kts` files\n#### <a name=\"r6.5.1\"></a> 6.5.1 kts files should wrap logic into top-level scope\nIt is still recommended wrapping logic inside functions and avoid using top-level statements for function calls or wrapping blocks of code\nin top-level scope functions like `run`.\n\n**Valid example**:\n```\nrun {\n    // some code\n}\n\nfun foo() {\n\n}\n```\n"
  },
  {
    "path": "RELEASING.md",
    "content": "# How to release a new version of diKTat\n\n* You should have permissions to push to the main repo\n* Simply create a new git tag with format `v*` and push it. Github workflow will perform release automatically.\n  \n  For example:\n  ```bash\n  $ git tag v1.0.0\n  $ git push origin --tags \n  ```\n  \nAfter the release workflow has started, version number is determined from tag. Binaries are uploaded to maven repo and \na new github release is created with fat jar.\n"
  },
  {
    "path": "_config.yml",
    "content": "theme: jekyll-theme-minimal"
  },
  {
    "path": "build.gradle.kts",
    "content": "import org.jetbrains.kotlin.incremental.createDirectory\nimport java.nio.file.Files\nimport java.nio.file.StandardCopyOption\n\n@Suppress(\"DSL_SCOPE_VIOLATION\", \"RUN_IN_SCRIPT\")  // https://github.com/gradle/gradle/issues/22797\nplugins {\n    id(\"com.saveourtool.diktat.buildutils.versioning-configuration\")\n    id(\"com.saveourtool.diktat.buildutils.git-hook-configuration\")\n    id(\"com.saveourtool.diktat.buildutils.code-quality-convention\")\n    id(\"com.saveourtool.diktat.buildutils.publishing-configuration\")\n    alias(libs.plugins.talaiot.base)\n    java\n    `maven-publish`\n}\n\ntalaiot {\n    metrics {\n        // disabling due to problems with OSHI on some platforms\n        performanceMetrics = false\n        environmentMetrics = false\n    }\n    publishers {\n        timelinePublisher = true\n    }\n}\n\nproject.description = \"diKTat kotlin formatter and fixer\"\n\nval libsFileName = \"libs.versions.toml\"\nval libsFile = rootProject.file(\"gradle/$libsFileName\")\nval libsFileBackup = rootProject.file(\"gradle/${libsFileName}_backup\")\n\ntasks.create(\"generateLibsForDiktatSnapshot\") {\n    val dir = rootProject.layout\n        .buildDirectory\n        .dir(\"diktat-snapshot\")\n        .get()\n        .asFile\n\n    val dependency = rootProject.project(\":diktat-gradle-plugin\")\n    dependsOn(dependency.let { \"${it.path}:publishToMavenLocal\" })\n\n    inputs.file(libsFile)\n    inputs.files(dependency.pomFile())\n    inputs.files(dependency.artifactFile())\n    inputs.property(\"project-version\", version.toString())\n    outputs.dir(dir)\n\n    doFirst {\n        dir.deleteRecursively()\n        dir.createDirectory()\n    }\n    doLast {\n        Files.readAllLines(libsFile.toPath())\n            .map { line ->\n                when {\n                    line.contains(\"diktat = \") -> \"diktat = \\\"$version\\\"\"\n                    else -> line\n                }\n            }\n            .let {\n                val libsFileForDiktatSnapshot = dir.resolve(libsFileName)\n                Files.write(libsFileForDiktatSnapshot.toPath(), it)\n                Files.move(libsFile.toPath(), libsFileBackup.toPath(), StandardCopyOption.REPLACE_EXISTING)\n                Files.copy(libsFileForDiktatSnapshot.toPath(), libsFile.toPath())\n            }\n\n        val artifactDir = dir.pathToMavenArtifact(dependency)\n            .also { it.createDirectory() }\n        Files.copy(dependency.pomFile().toPath(), artifactDir.resolve(dependency.pomFileName()).toPath())\n        Files.copy(dependency.artifactFile().toPath(), artifactDir.resolve(dependency.artifactFileName()).toPath())\n    }\n}\n\ntasks.create(\"rollbackLibsForDiktatSnapshot\") {\n    inputs.file(libsFileBackup)\n    outputs.file(libsFile)\n\n    doLast {\n        Files.deleteIfExists(libsFile.toPath())\n        Files.move(libsFileBackup.toPath(), libsFile.toPath())\n    }\n}\n\n/**\n * @param project\n * @return resolved path to directory according to maven coordinate\n */\nfun File.pathToMavenArtifact(project: Project): File = project.group.toString()\n    .split(\".\")\n    .fold(this) { dirToArtifact, newPart -> dirToArtifact.resolve(newPart) }\n    .resolve(project.name)\n    .resolve(project.version.toString())\n\n/**\n * @return generated pom.xml for project dependency\n */\nfun Project.pomFile(): File = layout.buildDirectory\n    .dir(\"publications\")\n    .map { publicationsDir ->\n        publicationsDir.dir(\"pluginMaven\")\n            .takeIf { it.asFile.exists() }\n            ?: publicationsDir.dir(\"maven\")\n    }\n    .map { it.file(\"pom-default.xml\").asFile }\n    .get()\n\n/**\n * @return file name of pom.xml for project\n */\nfun Project.pomFileName(): String = \"$name-$version.pom\"\n\n/**\n * @return generated artifact for project dependency\n */\nfun Project.artifactFile(): File = layout.buildDirectory\n    .dir(\"libs\")\n    .map { it.file(artifactFileName()).asFile }\n    .get()\n\n/**\n * @return file name of artifact for project dependency\n */\nfun Project.artifactFileName(): String = \"$name-$version.jar\"\n"
  },
  {
    "path": "detekt-config.yml",
    "content": "build:\n  maxIssues: 0\n  excludeCorrectable: false\n  weights:\n  # complexity: 2\n  # LongParameterList: 1\n  # style: 1\n  # comments: 1\n\nconfig:\n  validation: true\n  warningsAsErrors: false\n  # when writing own rules with new properties, exclude the property path e.g.: 'my_rule_set,.*>.*>[my_property]'\n  excludes: ''\n\nprocessors:\n  active: true\n  exclude:\n    - 'DetektProgressListener'\n  # - 'KtFileCountProcessor'\n  # - 'PackageCountProcessor'\n  # - 'ClassCountProcessor'\n  # - 'FunctionCountProcessor'\n  # - 'PropertyCountProcessor'\n  # - 'ProjectComplexityProcessor'\n  # - 'ProjectCognitiveComplexityProcessor'\n  # - 'ProjectLLOCProcessor'\n  # - 'ProjectCLOCProcessor'\n  # - 'ProjectLOCProcessor'\n  # - 'ProjectSLOCProcessor'\n  # - 'LicenseHeaderLoaderExtension'\n\nconsole-reports:\n  active: true\n  exclude:\n    - 'ProjectStatisticsReport'\n    - 'ComplexityReport'\n    - 'NotificationReport'\n    #  - 'FindingsReport'\n    - 'FileBasedFindingsReport'\n\noutput-reports:\n  active: true\n  exclude:\n  # - 'TxtOutputReport'\n  # - 'XmlOutputReport'\n  # - 'HtmlOutputReport'\n\ncomments:\n  active: true\n  excludes: ['**/test/**', '**/androidTest/**', '**/commonTest/**', '**/jvmTest/**', '**/jsTest/**', '**/iosTest/**']\n  AbsentOrWrongFileLicense:\n    active: false\n    licenseTemplateFile: 'license.template'\n    licenseTemplateIsRegex: false\n  CommentOverPrivateFunction:\n    active: false\n  CommentOverPrivateProperty:\n    active: false\n  EndOfSentenceFormat:\n    active: false\n    endOfSentenceFormat: '([.?!][ \\t\\n\\r\\f<])|([.?!:]$)'\n  UndocumentedPublicClass:\n    active: false\n    searchInNestedClass: true\n    searchInInnerClass: true\n    searchInInnerObject: true\n    searchInInnerInterface: true\n  UndocumentedPublicFunction:\n    active: false\n  UndocumentedPublicProperty:\n    active: false\n\ncomplexity:\n  active: true\n  ComplexCondition:\n    active: false\n    threshold: 4\n  ComplexInterface:\n    active: false\n    threshold: 10\n    includeStaticDeclarations: false\n    includePrivateDeclarations: false\n  CyclomaticComplexMethod:\n    active: true\n    threshold: 15\n    ignoreSingleWhenExpression: false\n    ignoreSimpleWhenEntries: false\n    ignoreNestingFunctions: false\n    nestingFunctions: [run, let, apply, with, also, use, forEach, isNotNull, ifNull]\n  LabeledExpression:\n    active: false\n    ignoredLabels: []\n  LargeClass:\n    active: true\n    threshold: 600\n  LongMethod:\n    active: true\n    threshold: 60\n  LongParameterList:\n    active: true\n    functionThreshold: 6\n    constructorThreshold: 7\n    ignoreDefaultParameters: false\n    ignoreDataClasses: true\n    ignoreAnnotated: []\n  MethodOverloading:\n    active: true\n    threshold: 6\n  NamedArguments:\n    active: false\n    threshold: 3\n  NestedBlockDepth:\n    active: false\n    threshold: 4\n  ReplaceSafeCallChainWithRun:\n    active: false\n  StringLiteralDuplication:\n    active: false\n    excludes: ['**/test/**', '**/androidTest/**', '**/commonTest/**', '**/jvmTest/**', '**/jsTest/**', '**/iosTest/**']\n    threshold: 3\n    ignoreAnnotation: true\n    excludeStringsWithLessThan5Characters: true\n    ignoreStringsRegex: '$^'\n  TooManyFunctions:\n    active: false\n    excludes: ['**/test/**', '**/androidTest/**', '**/commonTest/**', '**/jvmTest/**', '**/jsTest/**', '**/iosTest/**']\n    thresholdInFiles: 11\n    thresholdInClasses: 11\n    thresholdInInterfaces: 11\n    thresholdInObjects: 11\n    thresholdInEnums: 11\n    ignoreDeprecated: false\n    ignorePrivate: false\n    ignoreOverridden: false\n\ncoroutines:\n  active: true\n  GlobalCoroutineUsage:\n    active: true\n  RedundantSuspendModifier:\n    active: true\n  SleepInsteadOfDelay:\n    active: true\n  SuspendFunWithFlowReturnType:\n    active: true\n\nempty-blocks:\n  active: true\n  EmptyCatchBlock:\n    active: true\n    allowedExceptionNameRegex: '_|(ignore|expected).*'\n  EmptyClassBlock:\n    active: true\n  EmptyDefaultConstructor:\n    active: true\n  EmptyDoWhileBlock:\n    active: true\n  EmptyElseBlock:\n    active: true\n  EmptyFinallyBlock:\n    active: true\n  EmptyForBlock:\n    active: true\n  EmptyFunctionBlock:\n    active: true\n    ignoreOverridden: false\n  EmptyIfBlock:\n    active: true\n  EmptyInitBlock:\n    active: true\n  EmptyKtFile:\n    active: true\n  EmptySecondaryConstructor:\n    active: true\n  EmptyTryBlock:\n    active: true\n  EmptyWhenBlock:\n    active: true\n  EmptyWhileBlock:\n    active: true\n\nexceptions:\n  active: true\n  ExceptionRaisedInUnexpectedLocation:\n    active: true\n    methodNames: [toString, hashCode, equals, finalize]\n  InstanceOfCheckForException:\n    active: false\n    excludes: ['**/test/**', '**/androidTest/**', '**/commonTest/**', '**/jvmTest/**', '**/jsTest/**', '**/iosTest/**']\n  NotImplementedDeclaration:\n    active: true\n  ObjectExtendsThrowable:\n    active: true\n  PrintStackTrace:\n    active: true\n  RethrowCaughtException:\n    active: true\n  ReturnFromFinally:\n    active: true\n    ignoreLabeled: false\n  SwallowedException:\n    active: false\n    ignoredExceptionTypes:\n      - InterruptedException\n      - NumberFormatException\n      - ParseException\n      - MalformedURLException\n    allowedExceptionNameRegex: '_|(ignore|expected).*'\n  ThrowingExceptionFromFinally:\n    active: true\n  ThrowingExceptionInMain:\n    active: true\n  ThrowingExceptionsWithoutMessageOrCause:\n    active: true\n    excludes: ['**/test/**', '**/androidTest/**', '**/commonTest/**', '**/jvmTest/**', '**/jsTest/**', '**/iosTest/**']\n    exceptions:\n      - IllegalArgumentException\n      - IllegalStateException\n      - IOException\n  ThrowingNewInstanceOfSameException:\n    active: true\n  TooGenericExceptionCaught:\n    active: true\n    excludes: ['**/test/**', '**/androidTest/**', '**/commonTest/**', '**/jvmTest/**', '**/jsTest/**', '**/iosTest/**']\n    exceptionNames:\n      - ArrayIndexOutOfBoundsException\n      - Error\n      - Exception\n      - IllegalMonitorStateException\n      - NullPointerException\n      - IndexOutOfBoundsException\n      - RuntimeException\n      - Throwable\n    allowedExceptionNameRegex: '_|(ignore|expected).*'\n  TooGenericExceptionThrown:\n    active: true\n    exceptionNames:\n      - Error\n      - Exception\n      - Throwable\n      - RuntimeException\n\nnaming:\n  active: true\n  ClassNaming:\n    active: true\n    excludes: ['**/test/**', '**/androidTest/**', '**/commonTest/**', '**/jvmTest/**', '**/jsTest/**', '**/iosTest/**']\n    classPattern: '[A-Z][a-zA-Z0-9]*'\n  ConstructorParameterNaming:\n    active: true\n    excludes: ['**/test/**', '**/androidTest/**', '**/commonTest/**', '**/jvmTest/**', '**/jsTest/**', '**/iosTest/**']\n    parameterPattern: '[a-z][A-Za-z0-9]*'\n    privateParameterPattern: '[a-z][A-Za-z0-9]*'\n    excludeClassPattern: '$^'\n  EnumNaming:\n    active: true\n    excludes: ['**/test/**', '**/androidTest/**', '**/commonTest/**', '**/jvmTest/**', '**/jsTest/**', '**/iosTest/**']\n    enumEntryPattern: '[A-Z][_a-zA-Z0-9]*'\n  ForbiddenClassName:\n    active: false\n    excludes: ['**/test/**', '**/androidTest/**', '**/commonTest/**', '**/jvmTest/**', '**/jsTest/**', '**/iosTest/**']\n    forbiddenName: []\n  FunctionMaxLength:\n    active: false\n    excludes: ['**/test/**', '**/androidTest/**', '**/commonTest/**', '**/jvmTest/**', '**/jsTest/**', '**/iosTest/**']\n    maximumFunctionNameLength: 30\n  FunctionMinLength:\n    active: false\n    excludes: ['**/test/**', '**/androidTest/**', '**/commonTest/**', '**/jvmTest/**', '**/jsTest/**', '**/iosTest/**']\n    minimumFunctionNameLength: 3\n  FunctionNaming:\n    active: true\n    excludes: ['**/test/**', '**/androidTest/**', '**/commonTest/**', '**/jvmTest/**', '**/jsTest/**', '**/iosTest/**']\n    functionPattern: '([a-z][a-zA-Z0-9]*)|(`.*`)'\n    excludeClassPattern: '$^'\n    ignoreAnnotated: ['Composable']\n  FunctionParameterNaming:\n    active: true\n    excludes: ['**/test/**', '**/androidTest/**', '**/commonTest/**', '**/jvmTest/**', '**/jsTest/**', '**/iosTest/**']\n    parameterPattern: '[a-z][A-Za-z0-9]*'\n    excludeClassPattern: '$^'\n  InvalidPackageDeclaration:\n    active: false\n    excludes: ['*.kts']\n    rootPackage: ''\n  MatchingDeclarationName:\n    active: true\n    mustBeFirst: true\n  MemberNameEqualsClassName:\n    active: true\n    ignoreOverridden: true\n  NoNameShadowing:\n    active: false\n  NonBooleanPropertyPrefixedWithIs:\n    active: false\n    excludes: ['**/test/**', '**/androidTest/**', '**/commonTest/**', '**/jvmTest/**', '**/jsTest/**', '**/iosTest/**']\n  ObjectPropertyNaming:\n    active: true\n    excludes: ['**/test/**', '**/androidTest/**', '**/commonTest/**', '**/jvmTest/**', '**/jsTest/**', '**/iosTest/**']\n    constantPattern: '[A-Za-z][_A-Za-z0-9]*'\n    propertyPattern: '[A-Za-z][_A-Za-z0-9]*'\n    privatePropertyPattern: '(_)?[A-Za-z][_A-Za-z0-9]*'\n  PackageNaming:\n    active: true\n    excludes: ['**/test/**', '**/androidTest/**', '**/commonTest/**', '**/jvmTest/**', '**/jsTest/**', '**/iosTest/**']\n    packagePattern: '[a-z]+(\\.[a-z][A-Za-z0-9]*)*'\n  TopLevelPropertyNaming:\n    active: true\n    excludes: ['**/test/**', '**/androidTest/**', '**/commonTest/**', '**/jvmTest/**', '**/jsTest/**', '**/iosTest/**']\n    constantPattern: '[A-Z][_A-Z0-9]*'\n    propertyPattern: '[A-Za-z][_A-Za-z0-9]*'\n    privatePropertyPattern: '_?[A-Za-z][_A-Za-z0-9]*'\n  VariableMaxLength:\n    active: false\n    excludes: ['**/test/**', '**/androidTest/**', '**/commonTest/**', '**/jvmTest/**', '**/jsTest/**', '**/iosTest/**']\n    maximumVariableNameLength: 64\n  VariableMinLength:\n    active: false\n    excludes: ['**/test/**', '**/androidTest/**', '**/commonTest/**', '**/jvmTest/**', '**/jsTest/**', '**/iosTest/**']\n    minimumVariableNameLength: 1\n  VariableNaming:\n    active: true\n    excludes: ['**/test/**', '**/androidTest/**', '**/commonTest/**', '**/jvmTest/**', '**/jsTest/**', '**/iosTest/**']\n    variablePattern: '[a-z][A-Za-z0-9]*'\n    privateVariablePattern: '(_)?[a-z][A-Za-z0-9]*'\n    excludeClassPattern: '$^'\n\nperformance:\n  active: true\n  ArrayPrimitive:\n    active: true\n  ForEachOnRange:\n    active: true\n    excludes: ['**/test/**', '**/androidTest/**', '**/commonTest/**', '**/jvmTest/**', '**/jsTest/**', '**/iosTest/**']\n  SpreadOperator:\n    active: true\n    excludes: ['**/test/**', '**/androidTest/**', '**/commonTest/**', '**/jvmTest/**', '**/jsTest/**', '**/iosTest/**']\n  UnnecessaryTemporaryInstantiation:\n    active: true\n\npotential-bugs:\n  active: true\n  CastToNullableType:\n    active: false\n  Deprecation:\n    active: true\n  DontDowncastCollectionTypes:\n    active: true\n  EqualsAlwaysReturnsTrueOrFalse:\n    active: true\n  EqualsWithHashCodeExist:\n    active: true\n  ExitOutsideMain:\n    active: false\n  ExplicitGarbageCollectionCall:\n    active: true\n  HasPlatformType:\n    active: false\n  IgnoredReturnValue:\n    active: true\n    restrictToConfig: true\n    returnValueAnnotations: ['*.CheckReturnValue', '*.CheckResult']\n  ImplicitDefaultLocale:\n    active: false\n  ImplicitUnitReturnType:\n    active: false\n    allowExplicitReturnType: true\n  InvalidRange:\n    active: true\n  IteratorHasNextCallsNextMethod:\n    active: true\n  IteratorNotThrowingNoSuchElementException:\n    active: true\n  LateinitUsage:\n    active: false\n    excludes: ['**/test/**', '**/androidTest/**', '**/commonTest/**', '**/jvmTest/**', '**/jsTest/**', '**/iosTest/**']\n    ignoreOnClassesPattern: ''\n  MapGetWithNotNullAssertionOperator:\n    active: false\n  NullableToStringCall:\n    active: false\n  UnconditionalJumpStatementInLoop:\n    active: false\n  UnnecessaryNotNullOperator:\n    active: true\n  UnnecessarySafeCall:\n    active: true\n  UnreachableCatchBlock:\n    active: false\n  UnreachableCode:\n    active: true\n  UnsafeCallOnNullableType:\n    active: true\n  UnsafeCast:\n    active: true\n  UnusedUnaryOperator:\n    active: false\n  UselessPostfixExpression:\n    active: false\n  WrongEqualsTypeParameter:\n    active: true\n\nstyle:\n  active: true\n  ClassOrdering:\n    active: true\n  CollapsibleIfStatements:\n    active: false\n  DataClassContainsFunctions:\n    active: false\n    conversionFunctionPrefix: 'to'\n  DataClassShouldBeImmutable:\n    active: false\n  DestructuringDeclarationWithTooManyEntries:\n    active: true\n    maxDestructuringEntries: 3\n  EqualsNullCall:\n    active: true\n  EqualsOnSignatureLine:\n    active: false\n  ExplicitCollectionElementAccessMethod:\n    active: false\n  ExplicitItLambdaParameter:\n    active: false\n  ExpressionBodySyntax:\n    active: false\n    includeLineWrapping: false\n  ForbiddenImport:\n    active: false\n    imports: []\n    forbiddenPatterns: ''\n  ForbiddenMethodCall:\n    active: true\n    methods: ['kotlin.io.println', 'kotlin.io.print']\n    excludes: [\"**/src/test/**\"]\n  ForbiddenPublicDataClass:\n    active: true\n    excludes: ['**']\n    ignorePackages: ['*.internal', '*.internal.*']\n  ForbiddenVoid:\n    active: false\n    ignoreOverridden: false\n    ignoreUsageInGenerics: false\n  FunctionOnlyReturningConstant:\n    active: true\n    ignoreOverridableFunction: true\n    ignoreActualFunction: true\n    excludedFunctions: 'describeContents'\n    ignoreAnnotated: ['dagger.Provides']\n  LibraryCodeMustSpecifyReturnType:\n    active: true\n    excludes: ['**']\n  LibraryEntitiesShouldNotBePublic:\n    active: true\n    excludes: ['**']\n  LoopWithTooManyJumpStatements:\n    active: true\n    maxJumpCount: 1\n  MagicNumber:\n    active: true\n    excludes: ['**/test/**', '**/androidTest/**', '**/commonTest/**', '**/jvmTest/**', '**/jsTest/**', '**/iosTest/**']\n    ignoreNumbers: ['-1', '0', '1', '2']\n    ignoreHashCodeFunction: true\n    ignorePropertyDeclaration: false\n    ignoreLocalVariableDeclaration: false\n    ignoreConstantDeclaration: true\n    ignoreCompanionObjectPropertyDeclaration: true\n    ignoreAnnotation: false\n    ignoreNamedArgument: true\n    ignoreEnums: false\n    ignoreRanges: false\n    ignoreExtensionFunctions: true\n  MandatoryBracesLoops:\n    active: false\n  MaxLineLength:\n    active: true\n    maxLineLength: 180\n    excludePackageStatements: true\n    excludeImportStatements: true\n    excludeCommentStatements: false\n  MayBeConst:\n    active: true\n  ModifierOrder:\n    active: true\n  MultilineLambdaItParameter:\n    active: false\n  NestedClassesVisibility:\n    active: true\n  NewLineAtEndOfFile:\n    active: true\n  NoTabs:\n    active: false\n  OptionalAbstractKeyword:\n    active: true\n  OptionalUnit:\n    active: false\n  PreferToOverPairSyntax:\n    active: false\n  ProtectedMemberInFinalClass:\n    active: true\n  RedundantExplicitType:\n    active: false\n  RedundantHigherOrderMapUsage:\n    active: true\n  RedundantVisibilityModifierRule:\n    active: false\n  ReturnCount:\n    active: false\n    max: 4\n    excludedFunctions: 'equals'\n    excludeLabeled: false\n    excludeReturnFromLambda: true\n    excludeGuardClauses: false\n  SafeCast:\n    active: true\n  SerialVersionUIDInSerializableClass:\n    active: true\n  SpacingBetweenPackageAndImports:\n    active: false\n  ThrowsCount:\n    active: true\n    max: 2\n  TrailingWhitespace:\n    active: false\n  UnderscoresInNumericLiterals:\n    active: false\n    acceptableLength: 5\n  UnnecessaryAbstractClass:\n    active: true\n    ignoreAnnotated: ['dagger.Module']\n  UnnecessaryAnnotationUseSiteTarget:\n    active: false\n  UnnecessaryApply:\n    active: true\n  UnnecessaryFilter:\n    active: false\n  UnnecessaryInheritance:\n    active: true\n  UnnecessaryLet:\n    active: false\n  UnnecessaryParentheses:\n    active: false\n  UntilInsteadOfRangeTo:\n    active: false\n  UnusedImports:\n    active: false\n  UnusedPrivateClass:\n    active: true\n  UnusedPrivateMember:\n    active: false\n    allowedNames: '(_|ignored|expected|serialVersionUID)'\n  UseArrayLiteralsInAnnotations:\n    active: false\n  UseCheckNotNull:\n    active: false\n  UseCheckOrError:\n    active: false\n  UseDataClass:\n    active: false\n    allowVars: false\n  UseEmptyCounterpart:\n    active: true\n  UseIfEmptyOrIfBlank:\n    active: true\n  UseIfInsteadOfWhen:\n    active: false\n  UseIsNullOrEmpty:\n    active: true\n  UseOrEmpty:\n    active: false\n  UseRequire:\n    active: false\n  UseRequireNotNull:\n    active: true\n  UselessCallOnNotNull:\n    active: true\n  UtilityClassWithPublicConstructor:\n    active: true\n  VarCouldBeVal:\n    active: true\n    ignoreAnnotated: ['org.apache.maven.plugins.annotations.Parameter']\n  WildcardImport:\n    active: true\n    excludes: ['**/test/**', '**/androidTest/**', '**/commonTest/**', '**/jvmTest/**', '**/jsTest/**', '**/iosTest/**']\n    excludeImports: ['com.saveourtool.diktat.ruleset.utils.*', 'java.util.*', 'kotlinx.android.synthetic.*', 'kotlinx.serialization']\n"
  },
  {
    "path": "diktat-analysis.yml",
    "content": "# Common configuration\n- name: DIKTAT_COMMON\n  enabled: true\n  configuration:\n    # put your package name here - it will be autofixed and checked\n    domainName: com.saveourtool.diktat\n    # testDirs: test\n    # can also use chapter names here (not only numbers)\n    # expected values:  disabledChapters: \"Naming, Comments, General, Variables, Functions, Classes\"\n    # or: \"1, 2, 3, 4, 5, 6\"\n    disabledChapters: \"\"\n    testDirs: test\n    kotlinVersion: 2.1\n    srcDirectories: \"main\"\n# Checks that the Class/Enum/Interface name matches Pascal case\n- name: CLASS_NAME_INCORRECT\n  enabled: true\n# Checks that CONSTANT (treated as const val from companion object or class level) is in non UPPER_SNAKE_CASE\n- name: CONSTANT_UPPERCASE\n  enabled: true\n  configuration:\n    exceptionConstNames: \"serialVersionUID\"\n# Checks that enum value is in upper SNAKE_CASE or in PascalCase depending on the config. UPPER_SNAKE_CASE is the default, but can be changed by 'enumStyle' config\n- name: ENUM_VALUE\n  enabled: true\n  configuration:\n    # Two options: SNAKE_CASE (default), PascalCase\n    enumStyle: SNAKE_CASE\n# Checks that class which extends any Exception class has Exception suffix\n- name: EXCEPTION_SUFFIX\n  enabled: true\n# Checks that file name has extension\n- name: FILE_NAME_INCORRECT\n  enabled: true\n# Checks that file name matches class name, if it is only one class in file\n- name: FILE_NAME_MATCH_CLASS\n  enabled: true\n# Checks that functions/methods which return boolean have special prefix like \"is/should/e.t.c\"\n- name: FUNCTION_BOOLEAN_PREFIX\n  enabled: true\n  configuration:\n    allowedPrefixes: \"\" # A list of functions that return boolean and are allowed to use. Input is in a form \"foo, bar\".\n# Checks that function/method name is in lowerCamelCase\n- name: FUNCTION_NAME_INCORRECT_CASE\n  enabled: true\n# Checks that generic name doesn't contain more than 1 letter (capital). It can be followed by numbers, example: T12, T\n- name: GENERIC_NAME\n  enabled: true\n# Identifier length should be in range [2,64] except names that used in industry like {i, j} and 'e' for catching exceptions\n- name: IDENTIFIER_LENGTH\n  enabled: true\n# Checks that the object matches PascalCase\n- name: OBJECT_NAME_INCORRECT\n  enabled: true\n# Checks that package name is in correct (lower) case\n- name: PACKAGE_NAME_INCORRECT_CASE\n  enabled: true\n# Checks that package name starts with the company's domain\n- name: PACKAGE_NAME_INCORRECT_PREFIX\n  enabled: true\n# Checks that package name does not have incorrect symbols like underscore or non-ASCII letters/digits\n- name: PACKAGE_NAME_INCORRECT_SYMBOLS\n  enabled: true\n# Checks that the path for a file matches with a package name\n- name: PACKAGE_NAME_INCORRECT_PATH\n  enabled: true\n# Checks that package name is in the file\n- name: PACKAGE_NAME_MISSING\n  enabled: true\n# Checks that variable does not have prefix (like mVariable or M_VARIABLE)\n- name: VARIABLE_HAS_PREFIX\n  enabled: true\n# Checks that variable does not contain one single letter, only exceptions are fixed names that used in industry like {i, j}\n- name: VARIABLE_NAME_INCORRECT\n  enabled: true\n# Checks that the name of variable is in lowerCamelCase and contains only ASCII letters\n- name: VARIABLE_NAME_INCORRECT_FORMAT\n  enabled: true\n# Checks that functions have kdoc\n- name: MISSING_KDOC_ON_FUNCTION\n  enabled: true\n# Checks that on file level internal or public class or function has missing KDoc\n- name: MISSING_KDOC_TOP_LEVEL\n  enabled: true\n# Checks that accessible internal elements (protected, public, internal) in a class are documented\n- name: MISSING_KDOC_CLASS_ELEMENTS\n  enabled: true\n# Checks that accessible method parameters are documented in KDoc\n- name: KDOC_WITHOUT_PARAM_TAG\n  enabled: true\n# Checks that accessible method explicit return type is documented in KDoc\n- name: KDOC_WITHOUT_RETURN_TAG\n  enabled: true\n# Checks that accessible method throw keyword is documented in KDoc\n- name: KDOC_WITHOUT_THROWS_TAG\n  enabled: true\n# Checks that KDoc is not empty\n- name: KDOC_EMPTY_KDOC\n  enabled: true\n# Checks that underscore is correctly used to split package naming\n- name: INCORRECT_PACKAGE_SEPARATOR\n  enabled: true\n# Checks that code block doesn't contain kdoc comments\n- name: COMMENTED_BY_KDOC\n  enabled: true\n# Checks that there is no @deprecated tag in kdoc\n- name: KDOC_NO_DEPRECATED_TAG\n  enabled: true\n# Checks that there is no empty content in kdoc tags\n- name: KDOC_NO_EMPTY_TAGS\n  enabled: true\n# Checks that there is only one space after kdoc tag\n- name: KDOC_WRONG_SPACES_AFTER_TAG\n  enabled: true\n# Checks tags order in kDoc. `@param`, `@return`, `@throws`\n- name: KDOC_WRONG_TAGS_ORDER\n  enabled: true\n# Checks that there is no newline of empty KDoc line (with leading asterisk) between `@param`, `@return`, `@throws` tags\n- name: KDOC_NO_NEWLINES_BETWEEN_BASIC_TAGS\n  enabled: true\n# Checks that block of tags @param, @return, @throws is separated from previous part of KDoc by exactly one empty line\n- name: KDOC_NEWLINES_BEFORE_BASIC_TAGS\n  enabled: true\n# Checks that special tags `@apiNote`, `@implNote`, `@implSpec` have exactly one empty line after\n- name: KDOC_NO_NEWLINE_AFTER_SPECIAL_TAGS\n  enabled: true\n# Checks that KDoc does not contain single line with words 'return', 'get' or 'set'\n- name: KDOC_TRIVIAL_KDOC_ON_FUNCTION\n  enabled: true\n# Checks that kdoc does not contain @author tag or date\n- name: KDOC_CONTAINS_DATE_OR_AUTHOR\n  enabled: true\n  configuration:\n    versionRegex: \\d+\\.\\d+\\.\\d+[-.\\w\\d]*\n# Checks that there is newline after header KDoc\n- name: HEADER_WRONG_FORMAT\n  enabled: true\n# Checks that file with zero or >1 classes has header KDoc\n- name: HEADER_MISSING_IN_NON_SINGLE_CLASS_FILE\n  enabled: true\n# Checks that copyright exists on top of file and is properly formatted (as a block comment)\n- name: HEADER_MISSING_OR_WRONG_COPYRIGHT\n  enabled: true\n  configuration:\n    isCopyrightMandatory: false\n    copyrightText: ''\n# Checks that header kdoc is located before package directive\n- name: HEADER_NOT_BEFORE_PACKAGE\n  enabled: true\n# Checks that file does not contain lines > maxSize\n- name: FILE_IS_TOO_LONG\n  enabled: true\n  configuration:\n    # number of lines\n    maxSize: '2000'\n# Checks that file does not contain commented out code\n- name: COMMENTED_OUT_CODE\n  enabled: true\n# Checks that file does not contain only comments, imports and package directive\n- name: FILE_CONTAINS_ONLY_COMMENTS\n  enabled: true\n# Orders imports alphabetically\n- name: FILE_UNORDERED_IMPORTS\n  enabled: true\n  configuration:\n    # use logical imports grouping with sorting inside of a group\n    useRecommendedImportsOrder: true\n# Checks that general order of code parts is right\n- name: FILE_INCORRECT_BLOCKS_ORDER\n  enabled: true\n# Checks that there is exactly one line between code blocks\n- name: FILE_NO_BLANK_LINE_BETWEEN_BLOCKS\n  enabled: true\n# Checks that there is no wildcard imports. Exception: allowedWildcards\n- name: FILE_WILDCARD_IMPORTS\n  enabled: true\n  configuration:\n    # Allowed wildcards for imports (e.g. \"import com.saveourtool.diktat.*, import org.jetbrains.kotlin.*\")\n    allowedWildcards: \"kotlinx.serialization.*,com.saveourtool.diktat.ruleset.utils.*\"\n# Checks unused imports\n- name: UNUSED_IMPORT\n  enabled: true\n  configuration:\n    deleteUnusedImport: true\n# Checks that braces are used in if, else, when, for, do, and while statements. Exception: single line ternary operator statement\n- name: NO_BRACES_IN_CONDITIONALS_AND_LOOPS\n  enabled: true\n# Checks that the declaration part of a class-like code structures (class/interface/etc.) is in the proper order\n- name: WRONG_ORDER_IN_CLASS_LIKE_STRUCTURES\n  enabled: true\n# Checks that properties with comments are separated by a blank line\n- name: BLANK_LINE_BETWEEN_PROPERTIES\n  enabled: true\n# Checks top level order\n- name: TOP_LEVEL_ORDER\n  enabled: true\n# Checks that non-empty code blocks with braces follow the K&R style (1TBS or OTBS style)\n- name: BRACES_BLOCK_STRUCTURE_ERROR\n  enabled: true\n  configuration:\n    openBraceNewline: 'True'\n    closeBraceNewline: 'True'\n# Checks that indentation is correct\n- name: WRONG_INDENTATION\n  enabled: true\n  configuration:\n    # Is newline at the end of a file needed\n    newlineAtEnd: true\n    # If true: in parameter list when parameters are split by newline they are indented with two indentations instead of one\n    extendedIndentOfParameters: false\n    # If true: if first parameter in parameter list is on the same line as opening parenthesis, then other parameters can be aligned with it\n    alignedParameters: true\n    # If true, expression bodies which begin on a separate line are indented\n    # using a continuation indent. The default is false.\n    #\n    # This flag is called CONTINUATION_INDENT_FOR_EXPRESSION_BODIES in IDEA and\n    # ij_kotlin_continuation_indent_for_expression_bodies in .editorconfig.\n    extendedIndentForExpressionBodies: false\n    # If true: if expression is split by newline after operator like +/-/`*`, then the next line is indented with two indentations instead of one\n    extendedIndentAfterOperators: true\n    # If true: when dot qualified expression starts on a new line, this line will be indented with two indentations instead of one\n    extendedIndentBeforeDot: false\n    # The indentation size for each file\n    indentationSize: 4\n# Checks that there is no empty blocks in a file.\n# If allowEmptyBlocks is true, checks that it follows correct style (have a newline)\n- name: EMPTY_BLOCK_STRUCTURE_ERROR\n  enabled: true\n  configuration:\n    # Whether a newline after `{` is required in an empty block\n    styleEmptyBlockWithNewline: 'True'\n    allowEmptyBlocks: 'False'\n# Checks that there is no more than one statement per line\n- name: MORE_THAN_ONE_STATEMENT_PER_LINE\n  enabled: true\n# Checks that the line length is < lineLength parameter\n- name: LONG_LINE\n  enabled: true\n  configuration:\n    lineLength: '180'\n# Checks that semicolons are not used at the end of a line\n- name: REDUNDANT_SEMICOLON\n  enabled: true\n# Checks that line breaks follow code style guide: rule 3.6\n- name: WRONG_NEWLINES\n  enabled: true\n  configuration:\n    # If the number of parameters on one line is more than this threshold, all parameters will be placed on separate lines.\n    maxParametersInOneLine: 2\n    # 3 by default.\n    maxCallsInOneLine: 3\n# Checks trailing comma\n- name: TRAILING_COMMA\n  enabled: true\n  configuration:\n    # VALUE_ARGUMENT\n    valueArgument: false\n    # VALUE_PARAMETER\n    valueParameter: false\n    # REFERENCE_EXPRESSION\n    indices: false\n    # WHEN_CONDITION_WITH_EXPRESSION\n    whenConditions: false\n    # STRING_TEMPLATE\n    collectionLiteral: false\n    # TYPE_PROJECTION\n    typeArgument: false\n    # TYPE_PARAMETER\n    typeParameter: false\n    # DESTRUCTURING_DECLARATION_ENTRY\n    destructuringDeclaration: false\n# Inspection that checks if a long dot qualified expression is used in condition or as an argument\n- name: COMPLEX_EXPRESSION\n  enabled: true\n# Checks that there are not too many consecutive spaces in line\n- name: TOO_MANY_CONSECUTIVE_SPACES\n  enabled: true\n  configuration:\n    # Maximum allowed number of consecutive spaces (not counting indentation)\n    maxSpaces: '1'\n    # Whether formatting for enums should be kept without checking\n    saveInitialFormattingForEnums: false\n# Checks that blank lines are used correctly.\n# For example: triggers when there are too many blank lines between function declaration\n- name: TOO_MANY_BLANK_LINES\n  enabled: true\n# Checks that usage of horizontal spaces doesn't violate code style guide\n- name: WRONG_WHITESPACE\n  enabled: true\n# Checks that backticks (``) are not used in the identifier name, except the case when it is test method (marked with @Test annotation)\n- name: BACKTICKS_PROHIBITED\n  enabled: true\n  # all code blocks annotated with  @Nested, @ParameterizedTest (JUnit 5) will\n  # be ignored and not checked.\n  ignoreAnnotated: [ Nested, ParameterizedTest, IndentationTest ]\n# Checks that a single line concatenation of strings is not used\n- name: STRING_CONCATENATION\n  enabled: true\n# Checks that each when statement have else in the end\n- name: WHEN_WITHOUT_ELSE\n  enabled: true\n# Checks that annotation is on a single line\n- name: ANNOTATION_NEW_LINE\n  enabled: true\n# Checks that method annotated with `Preview` annotation is private and has Preview suffix\n- name: PREVIEW_ANNOTATION\n  enabled: true\n# Checks that enum structure is correct: enum entries should be separated by comma and line break and last entry should have semicolon in the end.\n- name: ENUMS_SEPARATED\n  enabled: true\n# Checks that value on integer or float constant is not too big\n- name: LONG_NUMERICAL_VALUES_SEPARATED\n  enabled: true\n  configuration:\n    # Maximum number of digits which are not split\n    maxNumberLength: '5'\n    # Maximum number of digits between separators\n    maxBlockLength: '3'\n# Checks magic number\n- name: MAGIC_NUMBER\n  enabled: true\n  configuration:\n    # Ignore numbers from test\n    ignoreTest: \"true\"\n    # Ignore numbers\n    ignoreNumbers: \"-1, 1, 0, 2, 0U, 1U, 2U, -1L, 0L, 1L, 2L, 0UL, 1UL, 2UL\"\n    # Is ignore override hashCode function\n    ignoreHashCodeFunction: \"true\"\n    # Is ignore property\n    ignorePropertyDeclaration: \"false\"\n    # Is ignore local variable\n    ignoreLocalVariableDeclaration: \"false\"\n    # Is ignore value parameter\n    ignoreValueParameter: \"true\"\n    # Is ignore constant\n    ignoreConstantDeclaration: \"true\"\n    # Is ignore property in companion object\n    ignoreCompanionObjectPropertyDeclaration: \"true\"\n    # Is ignore numbers in enum\n    ignoreEnums: \"false\"\n    # Is ignore number in ranges\n    ignoreRanges: \"false\"\n    # Is ignore number in extension function\n    ignoreExtensionFunctions: \"false\"\n    # Is ignore number in pairs created using to\n    ignorePairsCreatedUsingTo: \"false\"\n# Checks that order of enum values or constant property inside companion is correct\n- name: WRONG_DECLARATIONS_ORDER\n  enabled: true\n  configuration:\n    # Whether enum members should be sorted alphabetically\n    sortEnum: true\n    # Whether class properties should be sorted alphabetically\n    sortProperty: true\n# Checks that multiple modifiers sequence is in the correct order\n- name: WRONG_MULTIPLE_MODIFIERS_ORDER\n  enabled: true\n# Checks that identifier has appropriate name (See table of rule 1.2 part 6)\n- name: CONFUSING_IDENTIFIER_NAMING\n  enabled: true\n# Checks year in the copyright\n- name: WRONG_COPYRIGHT_YEAR\n  enabled: true\n# Inspection that checks if local variables are declared close to the first usage site\n- name: LOCAL_VARIABLE_EARLY_DECLARATION\n  enabled: true\n# Try to avoid initialize val by null (e.g. val a: Int? = null -> val a: Int = 0)\n- name: NULLABLE_PROPERTY_TYPE\n  enabled: true\n# Inspection that checks if there is a blank line before kDoc and none after\n- name: WRONG_NEWLINES_AROUND_KDOC\n  enabled: true\n# Inspection that checks if there is no blank lines before first comment\n- name: FIRST_COMMENT_NO_BLANK_LINE\n  enabled: true\n# Inspection that checks if there are blank lines between code and comment and between code start token and comment's text\n- name: COMMENT_WHITE_SPACE\n  enabled: true\n  configuration:\n    maxSpacesBeforeComment: 2\n    maxSpacesInComment: 1\n# Inspection that checks if all comment's are inside if-else code blocks. Exception is general if comment\n- name: IF_ELSE_COMMENTS\n  enabled: true\n# Type aliases provide alternative names for existing types when type's reference text is longer 25 chars\n- name: TYPE_ALIAS\n  enabled: true\n  configuration:\n    typeReferenceLength: '25' # max length of type reference\n# Checks if casting can be omitted\n- name: SMART_CAST_NEEDED\n  enabled: true\n# Checks that variables of generic types have explicit type declaration\n- name: GENERIC_VARIABLE_WRONG_DECLARATION\n  enabled: true\n# Inspection that checks if string template has redundant curly braces\n- name: STRING_TEMPLATE_CURLY_BRACES\n  enabled: true\n# Variables with `val` modifier - are immutable (read-only). Usage of such variables instead of `var` variables increases\n# robustness and readability of code, because `var` variables can be reassigned several times in the business logic.\n# This rule prohibits usage of `var`s as local variables - the only exception is accumulators and counters\n- name: SAY_NO_TO_VAR\n  enabled: true\n# Inspection that checks if string template has redundant quotes\n- name: STRING_TEMPLATE_QUOTES\n  enabled: true\n# Check if there are redundant nested if-statements, which could be collapsed into a single one by concatenating their conditions\n- name: COLLAPSE_IF_STATEMENTS\n  enabled: true\n  configuration:\n    startCollapseFromNestedLevel: 2\n# Checks that floating-point values are not used in arithmetic expressions\n- name: FLOAT_IN_ACCURATE_CALCULATIONS\n  enabled: true\n# Checks that function length isn't too long\n- name: TOO_LONG_FUNCTION\n  enabled: true\n  configuration:\n    maxFunctionLength: 35 # max length of function\n    isIncludeHeader: false # count function's header\n# Warns if there are nested functions\n- name: AVOID_NESTED_FUNCTIONS\n  enabled: true\n# Checks that lambda inside function parameters is in the end\n- name: LAMBDA_IS_NOT_LAST_PARAMETER\n  enabled: true\n# Checks that function doesn't contains too many parameters\n- name: TOO_MANY_PARAMETERS\n  enabled: true\n  configuration:\n    maxParameterListSize: '5' # max parameters size\n# Checks that function doesn't have too many nested blocks\n- name: NESTED_BLOCK\n  enabled: true\n  configuration:\n    maxNestedBlockQuantity: '4'\n# Checks that function use default values, instead overloading\n- name: WRONG_OVERLOADING_FUNCTION_ARGUMENTS\n  enabled: true\n# Checks that using runBlocking inside async block code\n- name: RUN_BLOCKING_INSIDE_ASYNC\n  enabled: true\n# Checks that the long lambda has parameters\n- name: TOO_MANY_LINES_IN_LAMBDA\n  enabled: true\n  configuration:\n    maxLambdaLength: 10 # max length of lambda without parameters\n# Checks that using unnecessary, custom label\n- name: CUSTOM_LABEL\n  enabled: true\n# Checks that outer lambda has explicit parameter name\n- name: PARAMETER_NAME_IN_OUTER_LAMBDA\n  enabled: true\n  configuration:\n    strictMode: true # don't let outer lambdas have `it` as parameter\n# Checks that property in constructor doesn't contain comment\n- name: KDOC_NO_CONSTRUCTOR_PROPERTY\n  enabled: true\n  configuration:\n    isParamTagsForParameters: false # create param tags for parameters without val or var\n    isParamTagsForPrivateProperties: false # create param tags for private properties\n    isParamTagsForGenericTypes: false # create param tags for generic types\n# Checks that property in KDoc present in class\n- name: KDOC_EXTRA_PROPERTY\n  enabled: true\n# There's a property in KDoc which is already present\n- name: KDOC_DUPLICATE_PROPERTY\n  enabled: true\n# Checks that KDoc in constructor has property tag but with comment inside constructor\n- name: KDOC_NO_CONSTRUCTOR_PROPERTY_WITH_COMMENT\n  enabled: true\n# if a class has single constructor, it should be converted to a primary constructor\n- name: SINGLE_CONSTRUCTOR_SHOULD_BE_PRIMARY\n  enabled: true\n# Checks if class can be made as data class\n- name: USE_DATA_CLASS\n  enabled: true\n# Checks that never use the name of a variable in the custom getter or setter\n- name: WRONG_NAME_OF_VARIABLE_INSIDE_ACCESSOR\n  enabled: true\n# Checks that classes have only one init block\n- name: MULTIPLE_INIT_BLOCKS\n  enabled: true\n# Checks that there are abstract functions in abstract class\n- name: CLASS_SHOULD_NOT_BE_ABSTRACT\n  enabled: true\n# Checks if there are any trivial getters or setters\n- name: TRIVIAL_ACCESSORS_ARE_NOT_RECOMMENDED\n  enabled: true\n# Checks that no custom getters and setters are used for properties. It is a more wide rule than TRIVIAL_ACCESSORS_ARE_NOT_RECOMMENDED\n# Kotlin compiler automatically generates `get` and `set` methods for properties and also lets the possibility to override it.\n# But in all cases it is very confusing when `get` and `set` are overridden for a developer who uses this particular class.\n# Developer expects to get the value of the property, but receives some unknown value and some extra side effect hidden by the custom getter/setter.\n# Use extra functions for it instead.\n- name: CUSTOM_GETTERS_SETTERS\n  enabled: true\n# Checks if null-check was used explicitly (for example: if (a == null))\n# Try to avoid explicit null checks (explicit comparison with `null`)\n# Kotlin is declared as [Null-safe](https://kotlinlang.org/docs/reference/null-safety.html) language.\n# But Kotlin architects wanted Kotlin to be fully compatible with Java, that's why `null` keyword was also introduced in Kotlin.\n# There are several code-structures that can be used in Kotlin to avoid null-checks. For example: `?:`,  `.let {}`, `.also {}`, e.t.c\n- name: AVOID_NULL_CHECKS\n  enabled: true\n# Checks if class instantiation can be wrapped in `apply` for better readability\n- name: COMPACT_OBJECT_INITIALIZATION\n  enabled: true\n# Checks explicit supertype qualification\n- name: USELESS_SUPERTYPE\n  enabled: true\n# Checks if extension function with the same signature don't have related classes\n- name: EXTENSION_FUNCTION_SAME_SIGNATURE\n  enabled: true\n# Checks if there is empty primary constructor\n- name: EMPTY_PRIMARY_CONSTRUCTOR\n  enabled: true\n# In case of not using field keyword in property accessors,\n# there should be explicit backing property with the name of real property\n# Example: val table get() {if (_table == null) ...} -> table should have _table\n- name: NO_CORRESPONDING_PROPERTY\n  enabled: true\n# Checks if there is class/object that can be replace with extension function\n- name: AVOID_USING_UTILITY_CLASS\n  enabled: true\n# If there is stateless class it is preferred to use object\n- name: OBJECT_IS_PREFERRED\n  enabled: true\n# If there exists negated version of function you should prefer it instead of !functionCall\n- name: INVERSE_FUNCTION_PREFERRED\n  enabled: true\n# Checks if class can be converted to inline class\n- name: INLINE_CLASS_CAN_BE_USED\n  enabled: true\n# If file contains class, then it can't contain extension functions for the same class\n- name: EXTENSION_FUNCTION_WITH_CLASS\n  enabled: true\n# Check if kts script contains other functions except run code\n- name: RUN_IN_SCRIPT\n  enabled: true\n# Check if boolean expression can be simplified\n- name: COMPLEX_BOOLEAN_EXPRESSION\n  enabled: true\n# Check if range can replace with until or `rangeTo` function with range\n- name: CONVENTIONAL_RANGE\n  enabled: true\n  configuration:\n    isRangeToIgnore: false\n# Check if there is a call of print()\\println() or console.log(). Assumption that it's a debug print\n- name: DEBUG_PRINT\n  enabled: true\n# Check that typealias name is in PascalCase\n- name: TYPEALIAS_NAME_INCORRECT_CASE\n  enabled: true\n# Should change property length - 1 to property lastIndex\n- name: USE_LAST_INDEX\n  enabled: true\n# Only properties from the primary constructor should be documented in a @property tag in class KDoc\n- name: KDOC_NO_CLASS_BODY_PROPERTIES_IN_HEADER\n  enabled: true\n"
  },
  {
    "path": "diktat-api/build.gradle.kts",
    "content": "plugins {\n    id(\"com.saveourtool.diktat.buildutils.kotlin-jvm-configuration\")\n    id(\"com.saveourtool.diktat.buildutils.code-quality-convention\")\n    id(\"com.saveourtool.diktat.buildutils.publishing-default-configuration\")\n    alias(libs.plugins.kotlin.plugin.serialization)\n}\n\nproject.description = \"This module builds diktat-api\"\n\ndependencies {\n    implementation(libs.kotlin.compiler.embeddable)\n    implementation(libs.kotlinx.serialization.core)\n}\n\nval generateDiktatVersionFile by tasks.registering {\n    val outputDir = layout.buildDirectory.dir(\"generated/src\").get().asFile\n    val versionsFile = outputDir.resolve(\"generated/DiktatVersion.kt\")\n\n    val diktatVersion = version.toString()\n\n    inputs.property(\"diktat version\", diktatVersion)\n    outputs.dir(outputDir)\n\n    doFirst {\n        versionsFile.parentFile.mkdirs()\n        versionsFile.writeText(\n            \"\"\"\n            package generated\n\n            const val DIKTAT_VERSION = \"$diktatVersion\"\n\n            \"\"\".trimIndent()\n        )\n    }\n}\n\nkotlin.sourceSets.getByName(\"main\") {\n    kotlin.srcDir(\n        generateDiktatVersionFile.map {\n            it.outputs.files.singleFile\n        }\n    )\n}\n\nsequenceOf(\"diktatFix\", \"diktatCheck\").forEach { diktatTaskName ->\n    tasks.findByName(diktatTaskName)?.dependsOn(\n        generateDiktatVersionFile,\n        tasks.named(\"compileKotlin\"),\n        tasks.named(\"processResources\"),\n    )\n}\n"
  },
  {
    "path": "diktat-api/src/main/kotlin/com/saveourtool/diktat/Constants.kt",
    "content": "/**\n * This file contains common constants for Diktat\n */\n\npackage com.saveourtool.diktat\n\n/**\n * Common application name, that is used in plugins and can be used to Suppress all diktat inspections on the\n * particular code block with @Suppress(\"diktat\")\n */\nconst val DIKTAT = \"diktat\"\n\n/**\n * Default file name for config file\n */\nconst val DIKTAT_ANALYSIS_CONF = \"diktat-analysis.yml\"\n"
  },
  {
    "path": "diktat-api/src/main/kotlin/com/saveourtool/diktat/DiktatProcessor.kt",
    "content": "package com.saveourtool.diktat\n\nimport com.saveourtool.diktat.api.DiktatCallback\nimport java.nio.file.Path\n\n/**\n * Processor to run `diktat`\n */\ninterface DiktatProcessor {\n    /**\n     * Run `diktat fix` on provided [file] using [callback] for detected errors and returned formatted file content.\n     *\n     * @param file\n     * @param callback\n     * @return result of `diktat fix`\n     */\n    fun fix(file: Path, callback: DiktatCallback): String\n\n    /**\n     * Run `diktat fix` on provided [code] using [callback] for detected errors and returned formatted code.\n     *\n     * @param code\n     * @param virtualPath a path which should be taken into account in processing of [code]\n     * @param callback\n     * @return result of `diktat fix`\n     */\n    fun fix(\n        code: String,\n        virtualPath: Path?,\n        callback: DiktatCallback,\n    ): String\n\n    /**\n     * Run `diktat check` on provided [file] using [callback] for detected errors.\n     *\n     * @param file\n     * @param callback\n     */\n    fun check(file: Path, callback: DiktatCallback)\n\n    /**\n     * Run `diktat check` on provided [code] using [callback] for detected errors.\n     *\n     * @param code\n     * @param virtualPath a path which should be taken into account in processing of [code]\n     * @param callback\n     */\n    fun check(\n        code: String,\n        virtualPath: Path?,\n        callback: DiktatCallback,\n    )\n}\n"
  },
  {
    "path": "diktat-api/src/main/kotlin/com/saveourtool/diktat/DiktatProcessorFactory.kt",
    "content": "package com.saveourtool.diktat\n\nimport com.saveourtool.diktat.api.DiktatRuleSet\n\n/**\n * A factory to create [DiktatProcessor] using [DiktatRuleSet]\n */\n@FunctionalInterface\ninterface DiktatProcessorFactory : Function1<DiktatRuleSet, DiktatProcessor> {\n    /**\n     * @param diktatRuleSet\n     * @return created [DiktatProcessor] using [DiktatRuleSet]\n     */\n    override operator fun invoke(diktatRuleSet: DiktatRuleSet): DiktatProcessor\n}\n"
  },
  {
    "path": "diktat-api/src/main/kotlin/com/saveourtool/diktat/DiktatRunner.kt",
    "content": "package com.saveourtool.diktat\n\nimport com.saveourtool.diktat.api.DiktatProcessorListener\nimport com.saveourtool.diktat.api.DiktatProcessorListener.Companion.countErrorsAsProcessorListener\nimport com.saveourtool.diktat.api.DiktatReporter\nimport java.nio.file.Path\nimport java.util.concurrent.atomic.AtomicInteger\nimport kotlin.io.path.readText\nimport kotlin.io.path.writeText\n\nprivate typealias RunAction = (DiktatProcessor, DiktatProcessorListener) -> Unit\n\n/**\n * A runner for diktat on bunch of files using baseline and reporter\n *\n * @param diktatProcessor\n * @property diktatReporter\n */\ndata class DiktatRunner(\n    private val diktatProcessor: DiktatProcessor,\n    val diktatReporter: DiktatReporter,\n) {\n    private fun doRun(\n        args: DiktatRunnerArguments,\n        runAction: RunAction,\n    ): Int {\n        val errorCounter = AtomicInteger()\n        runAction(\n            diktatProcessor,\n            DiktatProcessorListener(\n                args.loggingListener,\n                diktatReporter,\n                errorCounter.countErrorsAsProcessorListener()\n            ),\n        )\n        return errorCounter.get()\n    }\n\n    /**\n     * Run `diktat fix` for all [DiktatRunnerArguments.files].\n     *\n     * @param args\n     * @param fileUpdateNotifier notifier about updated files\n     * @return count of detected errors\n     */\n    fun fixAll(\n        args: DiktatRunnerArguments,\n        fileUpdateNotifier: (Path) -> Unit,\n    ): Int = doRun(args) { processor, listener ->\n        listener.beforeAll(args.files)\n        args.files.forEach { file ->\n            listener.before(file)\n            val formattedContent = processor.fix(file) { error, isCorrected ->\n                listener.onError(file, error, isCorrected)\n            }\n            val fileContent = file.readText(Charsets.UTF_8)\n            if (fileContent != formattedContent) {\n                fileUpdateNotifier(file)\n                file.writeText(formattedContent, Charsets.UTF_8)\n            }\n            listener.after(file)\n        }\n        listener.afterAll()\n    }\n\n    /**\n     * Run `diktat check` for all [DiktatRunnerArguments.files].\n     *\n     * @param args\n     * @return count of detected errors\n     */\n    fun checkAll(\n        args: DiktatRunnerArguments,\n    ): Int = doRun(args) { processor, listener ->\n        listener.beforeAll(args.files)\n        args.files.forEach { file ->\n            listener.before(file)\n            processor.check(file) { error, isCorrected ->\n                listener.onError(file, error, isCorrected)\n            }\n            listener.after(file)\n        }\n        listener.afterAll()\n    }\n}\n"
  },
  {
    "path": "diktat-api/src/main/kotlin/com/saveourtool/diktat/DiktatRunnerArguments.kt",
    "content": "package com.saveourtool.diktat\n\nimport com.saveourtool.diktat.api.DiktatProcessorListener\nimport com.saveourtool.diktat.api.DiktatReporterCreationArguments\nimport java.io.InputStream\nimport java.nio.file.Path\n\n/**\n * Arguments for [DiktatRunner]\n *\n * @property configInputStream an input stream with config to load Diktat's rules or null to use default configs\n * @property sourceRootDir a common root dir for all provided [files]\n * @property files a collection of files which needs to be fixed\n * @property baselineFile an optional path to file with baseline\n * @property reporterArgsList list of arguments to create reporters to report result\n * @property loggingListener listener to log diktat runner phases, [DiktatProcessorListener.empty] by default\n */\ndata class DiktatRunnerArguments(\n    val configInputStream: InputStream?,\n    val sourceRootDir: Path?,\n    val files: Collection<Path>,\n    val baselineFile: Path?,\n    val reporterArgsList: List<DiktatReporterCreationArguments> = emptyList(),\n    val loggingListener: DiktatProcessorListener = DiktatProcessorListener.empty,\n)\n"
  },
  {
    "path": "diktat-api/src/main/kotlin/com/saveourtool/diktat/DiktatRunnerFactory.kt",
    "content": "package com.saveourtool.diktat\n\nimport com.saveourtool.diktat.api.DiktatBaseline\nimport com.saveourtool.diktat.api.DiktatBaseline.Companion.skipKnownErrors\nimport com.saveourtool.diktat.api.DiktatBaselineFactory\nimport com.saveourtool.diktat.api.DiktatProcessorListener\nimport com.saveourtool.diktat.api.DiktatReporter\nimport com.saveourtool.diktat.api.DiktatReporterFactory\nimport com.saveourtool.diktat.api.DiktatRuleConfig\nimport com.saveourtool.diktat.api.DiktatRuleConfigReader\nimport com.saveourtool.diktat.api.DiktatRuleSet\nimport com.saveourtool.diktat.api.DiktatRuleSetFactory\nimport java.nio.file.Path\n\n/**\n * A factory to create [DiktatRunner]\n *\n * @param diktatRuleConfigReader a reader for [DiktatRuleConfig]\n * @param diktatRuleSetFactory a factory for [DiktatRuleSet]\n * @param diktatProcessorFactory a factory for [DiktatProcessor]\n * @param diktatBaselineFactory a factory for [DiktatBaseline]\n * @property diktatReporterFactory a factory for [DiktatReporter]\n */\nclass DiktatRunnerFactory(\n    private val diktatRuleConfigReader: DiktatRuleConfigReader,\n    private val diktatRuleSetFactory: DiktatRuleSetFactory,\n    private val diktatProcessorFactory: DiktatProcessorFactory,\n    private val diktatBaselineFactory: DiktatBaselineFactory,\n    val diktatReporterFactory: DiktatReporterFactory,\n) : Function1<DiktatRunnerArguments, DiktatRunner> {\n    /**\n     * @param args\n     * @return an instance of [DiktatRunner] created using [args]\n     */\n    override fun invoke(args: DiktatRunnerArguments): DiktatRunner {\n        val diktatRuleConfigs = args.configInputStream?.let { diktatRuleConfigReader(it) }.orEmpty()\n        val diktatRuleSet = diktatRuleSetFactory(diktatRuleConfigs)\n        val processor = diktatProcessorFactory(diktatRuleSet)\n        val (baseline, baselineGenerator) = resolveBaseline(args.baselineFile, args.sourceRootDir)\n\n        val reporter = args.reporterArgsList\n            .map { diktatReporterFactory(it) }\n            .let { DiktatReporter.union(it) }\n\n        return DiktatRunner(\n            diktatProcessor = processor,\n            diktatReporter = DiktatReporter(reporter.skipKnownErrors(baseline), baselineGenerator),\n        )\n    }\n\n    private fun resolveBaseline(\n        baselineFile: Path?,\n        sourceRootDir: Path?,\n    ): Pair<DiktatBaseline, DiktatProcessorListener> = baselineFile\n        ?.let { diktatBaselineFactory.tryToLoad(it, sourceRootDir) }\n        ?.let { it to DiktatProcessorListener.empty }\n        ?: run {\n            val baselineGenerator = baselineFile?.let {\n                diktatBaselineFactory.generator(it, sourceRootDir)\n            } ?: DiktatProcessorListener.empty\n            DiktatBaseline.empty to baselineGenerator\n        }\n}\n"
  },
  {
    "path": "diktat-api/src/main/kotlin/com/saveourtool/diktat/api/DiktatBaseline.kt",
    "content": "package com.saveourtool.diktat.api\n\nimport com.saveourtool.diktat.util.DiktatProcessorListenerWrapper\nimport java.nio.file.Path\n\n/**\n * A base interface for Baseline\n */\nfun interface DiktatBaseline {\n    /**\n     * @param file\n     * @return a set of [DiktatError] found in baseline by [file]\n     */\n    fun errorsByFile(file: Path): Set<DiktatError>\n\n    companion object {\n        /**\n         * Empty [DiktatBaseline]\n         */\n        val empty: DiktatBaseline = DiktatBaseline { _ -> emptySet() }\n\n        /**\n         * @param baseline\n         * @return wrapped [DiktatProcessorListener] which skips known errors based on [baseline]\n         */\n        fun DiktatProcessorListener.skipKnownErrors(baseline: DiktatBaseline): DiktatProcessorListener = object : DiktatProcessorListenerWrapper<DiktatProcessorListener>(\n            this@skipKnownErrors\n        ) {\n            override fun doOnError(\n                wrappedValue: DiktatProcessorListener,\n                file: Path,\n                error: DiktatError,\n                isCorrected: Boolean\n            ) {\n                if (!baseline.errorsByFile(file).contains(error)) {\n                    wrappedValue.onError(file, error, isCorrected)\n                }\n            }\n\n            override fun doBeforeAll(wrappedValue: DiktatProcessorListener, files: Collection<Path>) = wrappedValue.beforeAll(files)\n            override fun doBefore(wrappedValue: DiktatProcessorListener, file: Path) = wrappedValue.before(file)\n            override fun doAfter(wrappedValue: DiktatProcessorListener, file: Path) = wrappedValue.after(file)\n            override fun doAfterAll(wrappedValue: DiktatProcessorListener) = wrappedValue.afterAll()\n        }\n    }\n}\n"
  },
  {
    "path": "diktat-api/src/main/kotlin/com/saveourtool/diktat/api/DiktatBaselineFactory.kt",
    "content": "package com.saveourtool.diktat.api\n\nimport java.nio.file.Path\n\n/**\n * A factory to load or generate [DiktatBaseline]\n */\ninterface DiktatBaselineFactory {\n    /**\n     * @param baselineFile\n     * @param sourceRootDir a dir to detect relative path for processing files\n     * @return Loaded [DiktatBaseline] from [baselineFile] or null if it gets an error in loading\n     */\n    fun tryToLoad(\n        baselineFile: Path,\n        sourceRootDir: Path?,\n    ): DiktatBaseline?\n\n    /**\n     * @param baselineFile\n     * @param sourceRootDir a dir to detect relative path for processing files\n     * @return [DiktatProcessorListener] which generates baseline in [baselineFile]\n     */\n    fun generator(\n        baselineFile: Path,\n        sourceRootDir: Path?,\n    ): DiktatProcessorListener\n}\n"
  },
  {
    "path": "diktat-api/src/main/kotlin/com/saveourtool/diktat/api/DiktatCallback.kt",
    "content": "package com.saveourtool.diktat.api\n\n/**\n * Callback for diktat process\n */\n@FunctionalInterface\nfun interface DiktatCallback : Function2<DiktatError, Boolean, Unit> {\n    /**\n     * Performs this callback on the given [error] taking into account [isCorrected] flag.\n     *\n     * @param error the error found by diktat\n     * @param isCorrected true if the error fixed by diktat\n     */\n    override fun invoke(error: DiktatError, isCorrected: Boolean)\n\n    companion object {\n        /**\n         * [DiktatCallback] that does nothing\n         */\n        val empty: DiktatCallback = DiktatCallback { _, _ -> }\n    }\n}\n"
  },
  {
    "path": "diktat-api/src/main/kotlin/com/saveourtool/diktat/api/DiktatError.kt",
    "content": "package com.saveourtool.diktat.api\n\n/**\n * Error found by `diktat`\n *\n * @property line line number (one-based)\n * @property col column number (one-based)\n * @property ruleId rule id\n * @property detail error message\n * @property canBeAutoCorrected true if the found error can be fixed\n */\ndata class DiktatError(\n    val line: Int,\n    val col: Int,\n    val ruleId: String,\n    val detail: String,\n    val canBeAutoCorrected: Boolean = false,\n)\n"
  },
  {
    "path": "diktat-api/src/main/kotlin/com/saveourtool/diktat/api/DiktatErrorEmitter.kt",
    "content": "package com.saveourtool.diktat.api\n\n/**\n * The **file-specific** error emitter, initialized and used in [DiktatRule] implementations.\n *\n * Since the file is indirectly a part of the state of a `DiktatRule`, the same\n * `DiktatRule` instance should **never be re-used** to check more than a single\n * file, or confusing effects (incl. race conditions) will occur.\n *\n * @see DiktatRule\n */\nfun interface DiktatErrorEmitter : Function3<Int, String, Boolean, Unit> {\n    /**\n     * @param offset\n     * @param errorMessage\n     * @param canBeAutoCorrected\n     */\n    override fun invoke(\n        offset: Int,\n        errorMessage: String,\n        canBeAutoCorrected: Boolean\n    )\n}\n"
  },
  {
    "path": "diktat-api/src/main/kotlin/com/saveourtool/diktat/api/DiktatProcessorListener.kt",
    "content": "package com.saveourtool.diktat.api\n\nimport com.saveourtool.diktat.util.DiktatProcessorListenerWrapper\nimport java.nio.file.Path\nimport java.util.concurrent.atomic.AtomicInteger\n\nprivate typealias DiktatProcessorListenerIterable = Iterable<DiktatProcessorListener>\n\n/**\n * A listener for [com.saveourtool.diktat.DiktatProcessor]\n */\ninterface DiktatProcessorListener {\n    /**\n     * Called once, before [com.saveourtool.diktat.DiktatProcessor] starts process a bunch of files.\n     *\n     * @param files\n     */\n    fun beforeAll(files: Collection<Path>): Unit = Unit\n\n    /**\n     * Called before each file when [com.saveourtool.diktat.DiktatProcessor] starts to process it.\n     *\n     * @param file\n     */\n    fun before(file: Path): Unit = Unit\n\n    /**\n     * Called on each error when [com.saveourtool.diktat.DiktatProcessor] detects such one.\n     *\n     * @param file\n     * @param error\n     * @param isCorrected\n     */\n    fun onError(\n        file: Path,\n        error: DiktatError,\n        isCorrected: Boolean\n    ): Unit = Unit\n\n    /**\n     * Called after each file when [com.saveourtool.diktat.DiktatProcessor] finished to process it.\n     *\n     * @param file\n     */\n    fun after(file: Path): Unit = Unit\n\n    /**\n     * Called once, after the processing of [com.saveourtool.diktat.DiktatProcessor] finished.\n     */\n    fun afterAll(): Unit = Unit\n\n    companion object {\n        /**\n         * An instance of [DiktatProcessorListener] that does nothing\n         */\n        @Suppress(\"EMPTY_BLOCK_STRUCTURE_ERROR\")\n        val empty = object : DiktatProcessorListener {}\n\n        /**\n         * @param listeners\n         * @return a single [DiktatProcessorListener] which uses all provided [listeners]\n         */\n        fun union(listeners: DiktatProcessorListenerIterable): DiktatProcessorListener = object : DiktatProcessorListenerWrapper<DiktatProcessorListenerIterable>(listeners) {\n            override fun doBeforeAll(wrappedValue: DiktatProcessorListenerIterable, files: Collection<Path>) = wrappedValue.forEach { it.beforeAll(files) }\n            override fun doBefore(wrappedValue: DiktatProcessorListenerIterable, file: Path) = wrappedValue.forEach { it.before(file) }\n            override fun doOnError(\n                wrappedValue: DiktatProcessorListenerIterable,\n                file: Path,\n                error: DiktatError,\n                isCorrected: Boolean\n            ) = wrappedValue.forEach { it.onError(file, error, isCorrected) }\n            override fun doAfter(wrappedValue: DiktatProcessorListenerIterable, file: Path) = wrappedValue.forEach { it.after(file) }\n            override fun doAfterAll(wrappedValue: DiktatProcessorListenerIterable) = wrappedValue.forEach(DiktatProcessorListener::afterAll)\n        }\n\n        /**\n         * @param listeners\n         * @return a single [DiktatProcessorListener] which uses all provided [listeners]\n         */\n        operator fun invoke(vararg listeners: DiktatProcessorListener): DiktatProcessorListener = union(listeners.asIterable())\n\n        /**\n         * @return An implementation of [DiktatProcessorListener] which counts [DiktatError]s\n         */\n        fun AtomicInteger.countErrorsAsProcessorListener(): DiktatProcessorListener = object : DiktatProcessorListener {\n            override fun onError(\n                file: Path,\n                error: DiktatError,\n                isCorrected: Boolean\n            ) {\n                if (!isCorrected) {\n                    incrementAndGet()\n                }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "diktat-api/src/main/kotlin/com/saveourtool/diktat/api/DiktatReporterCreationArguments.kt",
    "content": "/**\n * Contains a base interface and implementations for a container with arguments to create a reporter\n */\n\npackage com.saveourtool.diktat.api\n\nimport java.io.OutputStream\nimport java.nio.file.Path\n\n/**\n * Arguments to create [DiktatReporter] using [DiktatReporterFactory]\n */\nsealed interface DiktatReporterCreationArguments {\n    /**\n     * Type of [DiktatReporter] which needs to be created\n     */\n    val reporterType: DiktatReporterType\n\n    /**\n     * Output for [DiktatReporter]\n     */\n    val outputStream: OutputStream\n\n    /**\n     * Should [outputStream] be closed af the end of [DiktatReporter]\n     */\n    val closeOutputStreamAfterAll: Boolean\n\n    /**\n     * Directory to base source root to report relative paths in [DiktatReporter]\n     */\n    val sourceRootDir: Path?\n\n    companion object {\n        /**\n         * @param reporterType type of [DiktatReporter]\n         * @param outputStream stdout will be used when it's empty\n         * @param sourceRootDir a dir to detect relative path for processing files\n         * @param colorNameInPlain a color name for colorful output which is applicable for plain ([DiktatReporterType.PLAIN]) reporter only,\n         * `null` means to disable colorization.\n         * @param groupByFileInPlain a flag `groupByFile` which is applicable for plain ([DiktatReporterType.PLAIN]) reporter only.\n         * @return created [DiktatReporter]\n         */\n        operator fun invoke(\n            reporterType: DiktatReporterType,\n            outputStream: OutputStream?,\n            sourceRootDir: Path?,\n            colorNameInPlain: String? = null,\n            groupByFileInPlain: Boolean? = null,\n        ): DiktatReporterCreationArguments {\n            val (outputStreamOrStdout, closeOutputStreamAfterAll) = outputStream?.let { it to true } ?: (System.`out` to false)\n            return if (reporterType == DiktatReporterType.PLAIN) {\n                PlainDiktatReporterCreationArguments(\n                    outputStreamOrStdout, closeOutputStreamAfterAll, sourceRootDir, colorNameInPlain, groupByFileInPlain\n                )\n            } else {\n                require(colorNameInPlain == null) {\n                    \"colorization is applicable only for plain reporter\"\n                }\n                require(groupByFileInPlain == null) {\n                    \"groupByFile is applicable only for plain reporter\"\n                }\n                DiktatReporterCreationArgumentsImpl(\n                    reporterType, outputStreamOrStdout, closeOutputStreamAfterAll, sourceRootDir\n                )\n            }\n        }\n    }\n}\n\n/**\n * Implementation of [DiktatReporterCreationArguments] for [DiktatReporterType.PLAIN]\n *\n * @property outputStream\n * @property closeOutputStreamAfterAll\n * @property sourceRootDir\n * @property colorName name of color for colorful output, `null` means to disable colorization.\n * @property groupByFile\n */\ndata class PlainDiktatReporterCreationArguments(\n    override val outputStream: OutputStream,\n    override val closeOutputStreamAfterAll: Boolean,\n    override val sourceRootDir: Path?,\n    val colorName: String? = null,\n    val groupByFile: Boolean? = null,\n) : DiktatReporterCreationArguments {\n    override val reporterType: DiktatReporterType = DiktatReporterType.PLAIN\n}\n\n/**\n * @property reporterType\n * @property outputStream\n * @property closeOutputStreamAfterAll\n * @property sourceRootDir\n */\nprivate data class DiktatReporterCreationArgumentsImpl(\n    override val reporterType: DiktatReporterType,\n    override val outputStream: OutputStream,\n    override val closeOutputStreamAfterAll: Boolean,\n    override val sourceRootDir: Path?,\n) : DiktatReporterCreationArguments\n"
  },
  {
    "path": "diktat-api/src/main/kotlin/com/saveourtool/diktat/api/DiktatReporterFactory.kt",
    "content": "package com.saveourtool.diktat.api\n\ntypealias DiktatReporter = DiktatProcessorListener\n\n/**\n * A factory to create [DiktatReporter]\n */\ninterface DiktatReporterFactory : Function1<DiktatReporterCreationArguments, DiktatReporter> {\n    /**\n     * Names of color for plain output\n     */\n    val colorNamesInPlain: Set<String>\n\n    /**\n     * @param args\n     * @return created [DiktatReporter]\n     */\n    override operator fun invoke(\n        args: DiktatReporterCreationArguments,\n    ): DiktatReporter\n}\n"
  },
  {
    "path": "diktat-api/src/main/kotlin/com/saveourtool/diktat/api/DiktatReporterType.kt",
    "content": "package com.saveourtool.diktat.api\n\n/**\n * @property id\n * @property extension\n */\nenum class DiktatReporterType(\n    val id: String,\n    val extension: String,\n) {\n    CHECKSTYLE(\"checkstyle\", \"xml\"),\n    HTML(\"html\", \"html\"),\n    JSON(\"json\", \"json\"),\n    PLAIN(\"plain\", \"txt\"),\n    PLAIN_GROUP_BY_FILE(\"plain-group-by-file\", \"txt\"),\n    SARIF(\"sarif\", \"sarif\"),\n    ;\n}\n"
  },
  {
    "path": "diktat-api/src/main/kotlin/com/saveourtool/diktat/api/DiktatRule.kt",
    "content": "package com.saveourtool.diktat.api\n\nimport org.jetbrains.kotlin.com.intellij.lang.ASTNode\n\n/**\n * This is a base interface for diktat's rules\n */\ninterface DiktatRule : Function3<ASTNode, Boolean, DiktatErrorEmitter, Unit> {\n    /**\n     * A unique ID of this rule.\n     */\n    val id: String\n\n    /**\n     * This method is going to be executed for each node in AST (in DFS fashion).\n     *\n     * @param node AST node\n     * @param autoCorrect indicates whether rule should attempt autocorrection\n     * @param emitter a way for rule to notify about a violation (lint error)\n     */\n    override fun invoke(\n        node: ASTNode,\n        autoCorrect: Boolean,\n        emitter: DiktatErrorEmitter,\n    )\n}\n"
  },
  {
    "path": "diktat-api/src/main/kotlin/com/saveourtool/diktat/api/DiktatRuleConfig.kt",
    "content": "package com.saveourtool.diktat.api\n\nimport kotlinx.serialization.Serializable\n\n/**\n * Configuration of individual [DiktatRule]\n *\n * @property name name of the rule\n * @property enabled\n * @property configuration a map of strings with configuration options\n * @property ignoreAnnotated if a code block is marked with these annotations - it will not be checked by this rule\n */\n@Serializable\ndata class DiktatRuleConfig(\n    val name: String,\n    val enabled: Boolean = true,\n    val configuration: Map<String, String> = emptyMap(),\n    val ignoreAnnotated: Set<String> = emptySet(),\n)\n\n/**\n * Finds [DiktatRuleConfig] for particular [DiktatRuleNameAware] object.\n *\n * @param rule a [DiktatRuleNameAware] which configuration will be returned\n * @return [DiktatRuleConfig] for a particular rule if it is found, else null\n */\nfun List<DiktatRuleConfig>.findByRuleName(rule: DiktatRuleNameAware): DiktatRuleConfig? = this.find { it.name == rule.ruleName() }\n\n/**\n * checking if in yml config particular rule is enabled or disabled\n * (!) the default value is \"true\" (in case there is no config specified)\n *\n * @param rule a [DiktatRuleNameAware] which is being checked\n * @return true if rule is enabled in configuration, else false\n */\nfun List<DiktatRuleConfig>.isRuleEnabled(rule: DiktatRuleNameAware): Boolean {\n    val ruleMatched = findByRuleName(rule)\n    return ruleMatched?.enabled ?: true\n}\n\n/**\n * @param rule diktat inspection\n * @param annotations set of annotations that are annotating a block of code\n * @return true if the code block is marked with annotation that is in `ignored list` in the rule\n */\nfun List<DiktatRuleConfig>.isAnnotatedWithIgnoredAnnotation(rule: DiktatRuleNameAware, annotations: Set<String>): Boolean =\n    findByRuleName(rule)\n        ?.ignoreAnnotated\n        ?.map { it.trim() }\n        ?.map { it.trim('\"') }\n        ?.intersect(annotations)\n        ?.isNotEmpty()\n        ?: false\n"
  },
  {
    "path": "diktat-api/src/main/kotlin/com/saveourtool/diktat/api/DiktatRuleConfigReader.kt",
    "content": "package com.saveourtool.diktat.api\n\nimport java.io.InputStream\n\n/**\n * A reader for [DiktatRuleConfig]\n */\nfun interface DiktatRuleConfigReader : Function1<InputStream, List<DiktatRuleConfig>> {\n    /**\n     * @param inputStream\n     * @return parsed [DiktatRuleConfig]s\n     */\n    override operator fun invoke(inputStream: InputStream): List<DiktatRuleConfig>\n}\n"
  },
  {
    "path": "diktat-api/src/main/kotlin/com/saveourtool/diktat/api/DiktatRuleNameAware.kt",
    "content": "package com.saveourtool.diktat.api\n\n/**\n * This interface represents *name* of individual inspection in rule set.\n */\ninterface DiktatRuleNameAware {\n    /**\n     * @return name of this [DiktatRule]\n     */\n    fun ruleName(): String\n}\n"
  },
  {
    "path": "diktat-api/src/main/kotlin/com/saveourtool/diktat/api/DiktatRuleSet.kt",
    "content": "package com.saveourtool.diktat.api\n\n/**\n * A group of [DiktatRule]'s as a single set.\n *\n * @property rules diktat rules.\n */\ndata class DiktatRuleSet(\n    val rules: List<DiktatRule>\n)\n"
  },
  {
    "path": "diktat-api/src/main/kotlin/com/saveourtool/diktat/api/DiktatRuleSetFactory.kt",
    "content": "package com.saveourtool.diktat.api\n\n/**\n * A factory which creates a [DiktatRuleSet].\n */\nfun interface DiktatRuleSetFactory : Function1<List<DiktatRuleConfig>, DiktatRuleSet> {\n    /**\n     * @param rulesConfig all configurations for rules\n     * @return the default instance of [DiktatRuleSet]\n     */\n    override operator fun invoke(rulesConfig: List<DiktatRuleConfig>): DiktatRuleSet\n}\n"
  },
  {
    "path": "diktat-api/src/main/kotlin/com/saveourtool/diktat/common/config/rules/LegacyAliases.kt",
    "content": "/**\n * Contains typealias for legacy support\n */\n\npackage com.saveourtool.diktat.common.config.rules\n\nimport com.saveourtool.diktat.api.DiktatRuleConfig\nimport com.saveourtool.diktat.api.DiktatRuleNameAware\n\nconst val DIKTAT_CONF_PROPERTY = \"diktat.config.path\"\n\n/**\n * this constant will be used everywhere in the code to mark usage of Diktat ruleset\n *\n * Should be removed from Diktat's code and should be presented only in `diktat-ruleset`\n */\nconst val DIKTAT_RULE_SET_ID = \"diktat-ruleset\"\n\ntypealias RulesConfig = DiktatRuleConfig\ntypealias Rule = DiktatRuleNameAware\n"
  },
  {
    "path": "diktat-api/src/main/kotlin/com/saveourtool/diktat/util/DiktatProcessorListenerWrapper.kt",
    "content": "package com.saveourtool.diktat.util\n\nimport com.saveourtool.diktat.api.DiktatError\nimport com.saveourtool.diktat.api.DiktatProcessorListener\nimport java.nio.file.Path\n\n/**\n * A common wrapper for [DiktatProcessorListener]\n *\n * @property wrappedValue\n */\nopen class DiktatProcessorListenerWrapper<T : Any>(\n    val wrappedValue: T,\n) : DiktatProcessorListener {\n    override fun beforeAll(files: Collection<Path>): Unit = doBeforeAll(wrappedValue, files)\n\n    /**\n     * Called once, before [com.saveourtool.diktat.DiktatProcessor] starts process a bunch of files.\n     *\n     * @param wrappedValue\n     * @param files\n     */\n    protected open fun doBeforeAll(wrappedValue: T, files: Collection<Path>): Unit = Unit\n\n    override fun before(file: Path): Unit = doBefore(wrappedValue, file)\n\n    /**\n     * Called before each file when [com.saveourtool.diktat.DiktatProcessor] starts to process it.\n     *\n     * @param wrappedValue\n     * @param file\n     */\n    protected open fun doBefore(wrappedValue: T, file: Path): Unit = Unit\n\n    override fun onError(\n        file: Path,\n        error: DiktatError,\n        isCorrected: Boolean\n    ): Unit = doOnError(wrappedValue, file, error, isCorrected)\n\n    /**\n     * Called on each error when [com.saveourtool.diktat.DiktatProcessor] detects such one.\n     *\n     * @param wrappedValue\n     * @param file\n     * @param error\n     * @param isCorrected\n     */\n    protected open fun doOnError(\n        wrappedValue: T,\n        file: Path,\n        error: DiktatError,\n        isCorrected: Boolean\n    ): Unit = Unit\n\n    override fun after(file: Path): Unit = doAfter(wrappedValue, file)\n\n    /**\n     * Called after each file when [com.saveourtool.diktat.DiktatProcessor] finished to process it.\n     *\n     * @param wrappedValue\n     * @param file\n     */\n    protected open fun doAfter(wrappedValue: T, file: Path): Unit = Unit\n\n    override fun afterAll(): Unit = doAfterAll(wrappedValue)\n\n    /**\n     * Called once, after the processing of [com.saveourtool.diktat.DiktatProcessor] finished.\n     *\n     * @param wrappedValue\n     */\n    protected open fun doAfterAll(wrappedValue: T): Unit = Unit\n\n    companion object {\n        /**\n         * @return wrapped value [T] if it's possible\n         */\n        inline fun <reified T : Any> DiktatProcessorListener.tryUnwrap(): T? = (this as? DiktatProcessorListenerWrapper<*>)\n            ?.wrappedValue\n            ?.let { it as? T }\n\n        /**\n         * @return wrapped value [T] or an error\n         */\n        inline fun <reified T : Any> DiktatProcessorListener.unwrap(): T = tryUnwrap<T>()\n            ?: error(\"Unsupported wrapper of ${DiktatProcessorListener::class.java.simpleName} to ${T::class.simpleName}: ${this.javaClass.name}\")\n    }\n}\n"
  },
  {
    "path": "diktat-api/src/main/kotlin/com/saveourtool/diktat/util/FileUtils.kt",
    "content": "/**\n * Utility methods to work with file paths.\n */\n\npackage com.saveourtool.diktat.util\n\nimport java.nio.file.Path\nimport kotlin.io.path.extension\n\nprivate const val KOTLIN_EXTENSION = \"kt\"\nprivate const val KOTLIN_SCRIPT_EXTENSION = KOTLIN_EXTENSION + \"s\"\n\n/**\n * Checks if [this] [String] is a name of a kotlin script file by checking whether file extension equals 'kts'\n *\n * @return true if this is a kotlin script file name, false otherwise\n */\nfun String.isKotlinScript() = endsWith(\".$KOTLIN_SCRIPT_EXTENSION\", true)\n\n/**\n * Check if [this] [Path] is a kotlin script by checking whether an extension equals to 'kts'\n *\n * @return true if this is a kotlin script file name, false otherwise\n */\nfun Path.isKotlinScript() = this.extension.lowercase() == KOTLIN_SCRIPT_EXTENSION\n\n/**\n * Check if [this] [Path] is a kotlin code or script by checking whether an extension equals to `kt` or 'kts'\n *\n * @return true if this is a kotlin code or script file name, false otherwise\n */\nfun Path.isKotlinCodeOrScript() = this.extension.lowercase() in setOf(KOTLIN_EXTENSION, KOTLIN_SCRIPT_EXTENSION)\n"
  },
  {
    "path": "diktat-cli/README.md",
    "content": "# _diktat-cli_, the command-line client for [_diktat_](https://github.com/saveourtool/diktat)\n\n---\n\n# Table of contents\n1. [Features](#features)\n2. [Usage](#usage)\n3. [Option summary](#option-summary)\n4. [Exit code](#exit-codes)\n\n---\n\n## Features\n\n* Self-executable JAR in _UNIX Shell_ (requires installed _JAVA_)\n* BSD-compatible\n* Also works in Windows (_Git Bash_, _Cygwin_, or _MSys2_) via the dedicated _diktat.cmd_\n* Can be used as a regular uber JAR\n\n## Usage\n\n```shell\ndiktat [OPTION]... [FILE]...\n```\n\n## Option summary\n\n| Command-line switch                  | Meaning                                                                                                                                                                                                                |\n|:-------------------------------------|:-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|\n| `-c CONFIG`, `--config=CONFIG`       | Specify the location of the YAML configuration file. By default, `diktat-analysis.yml` in the current directory is used.                                                                                               |\n| `-m MODE`, `--mode MODE`             | Mode of `diktat` controls that `diktat` fixes or only finds any deviations from the code style.                                                                                                                        |\n| `-r REPORTER`, `--reporter=REPORTER` | The reporter to use to errors to `output`, one of: `plain`, `plain_group_by_file`, `json`, `sarif`, `checkstyle`, `html`.                                                                                              |\n| `-o OUTPUT`, `--output=OUTPUT`       | Redirect the reporter output to a file. Must be provided when the reporter is provided.                                                                                                                                |\n| `--group-by-file`                    | A flag to group found errors by files.                                                                                                                                                                                 |\n| `--color COLOR`                      | Colorize the output, one of: `BLACK`, `RED`, `GREEN`, `YELLOW`, `BLUE`, `MAGENTA`, `CYAN`, `LIGHT_GRAY`, `DARK_GRAY`, `LIGHT_RED`, `LIGHT_GREEN`, `LIGHT_YELLOW`, `LIGHT_BLUE`, `LIGHT_MAGENTA`, `LIGHT_CYAN`, `WHITE` |\n| `-l`, `--log-level`                  | Control the log level.                                                                                                                                                                                                 |\n| `-h`, `--help`                       | Display the help text and exit.                                                                                                                                                                                        |\n| `-l`, `--license`                    | Display the license and exit.                                                                                                                                                                                          |\n| `-v`, `--verbose`                    | Enable the verbose output.                                                                                                                                                                                             |\n| `-V`, `--version`                    | Output version information and exit.                                                                                                                                                                                   |\n\n## Exit codes\n\n| Exit code | Meaning                                                                                                             |\n|:----------|:--------------------------------------------------------------------------------------------------------------------|\n| 0         | _diKTat_ found no errors in your code                                                                               |\n| 1         | _diKTat_ reported some errors in your code                                                                          |\n| 2         | The JVM was not found (probably, you need to set up the JVM explicitly, using the `JAVA_HOME` environment variable) |\n| 3         | Incompatible _Bash_ version                                                                                         |\n"
  },
  {
    "path": "diktat-cli/build.gradle.kts",
    "content": "import com.saveourtool.diktat.buildutils.configurePublications\nimport com.github.jengelman.gradle.plugins.shadow.ShadowExtension\nimport org.jetbrains.kotlin.incremental.createDirectory\n\n@Suppress(\"DSL_SCOPE_VIOLATION\", \"RUN_IN_SCRIPT\")  // https://github.com/gradle/gradle/issues/22797\nplugins {\n    id(\"com.saveourtool.diktat.buildutils.kotlin-jvm-configuration\")\n    id(\"com.saveourtool.diktat.buildutils.code-quality-convention\")\n    id(\"com.saveourtool.diktat.buildutils.publishing-configuration\")\n    alias(libs.plugins.kotlin.plugin.serialization)\n    alias(libs.plugins.shadow)\n}\n\nproject.description = \"This module builds diktat-cli to run diktat as CLI using ktlint\"\n\ndependencies {\n    implementation(projects.diktatRunner)\n    implementation(libs.kotlinx.cli)\n    implementation(libs.kotlinx.serialization.core)\n    implementation(libs.kotlin.logging)\n    implementation(libs.slf4j.api)\n    implementation(libs.log4j2.core)\n    implementation(libs.log4j2.slf4j2)\n\n    testImplementation(projects.diktatKtlintEngine)\n    testImplementation(projects.diktatRules)\n    testImplementation(projects.diktatCommonTest)\n    testImplementation(libs.kaml)\n    testImplementation(libs.junit.jupiter)\n    testImplementation(libs.junit.platform.suite)\n    testImplementation(libs.assertj.core)\n}\n\nval addLicenseTask: TaskProvider<Task> = tasks.register(\"addLicense\") {\n    val licenseFile = rootProject.file(\"LICENSE\")\n    val outputDir = layout.buildDirectory\n        .dir(\"generated/src\")\n        .get()\n        .asFile\n\n    inputs.file(licenseFile)\n    outputs.dir(outputDir)\n\n    doLast {\n        licenseFile.copyTo(\n            outputDir.resolve(\"META-INF\").resolve(\"diktat\")\n                .also { it.createDirectory() }\n                .resolve(licenseFile.name),\n            overwrite = true\n        )\n    }\n}\n\nsourceSets.getByName(\"main\") {\n    resources.srcDir(\n        addLicenseTask.map {\n            it.outputs.files.singleFile\n        }\n    )\n}\n\ntasks.shadowJar {\n    archiveClassifier.set(\"\")\n    manifest {\n        attributes[\"Main-Class\"] = \"com.saveourtool.diktat.DiktatMainKt\"\n        attributes[\"Multi-Release\"] = true\n    }\n    duplicatesStrategy = DuplicatesStrategy.FAIL\n}\n\ntasks.register<DefaultTask>(\"shadowExecutableJar\") {\n    group = \"Distribution\"\n    dependsOn(tasks.shadowJar)\n\n    val scriptFile = project.file(\"src/main/script/header-diktat.sh\")\n    val shadowJarFile = tasks.shadowJar\n        .get()\n        .outputs\n        .files\n        .singleFile\n    val outputFile = project.layout\n        .buildDirectory\n        .file(shadowJarFile.name.removeSuffix(\".jar\"))\n\n    inputs.files(scriptFile, shadowJarFile)\n    outputs.file(outputFile)\n\n    doLast {\n        outputFile.get()\n            .asFile\n            .apply {\n                writeBytes(scriptFile.readBytes())\n                appendBytes(shadowJarFile.readBytes())\n                setExecutable(true, false)\n            }\n    }\n}\n\n// disable default jar\ntasks.named(\"jar\") {\n    enabled = false\n}\n\n// it triggers shadowJar with default build\ntasks {\n    build {\n        dependsOn(shadowJar)\n    }\n    test {\n        dependsOn(shadowJar)\n    }\n}\n\npublishing {\n    publications {\n        // it creates a publication for shadowJar\n        create<MavenPublication>(\"shadow\") {\n            // https://github.com/johnrengelman/shadow/issues/417#issuecomment-830668442\n            project.extensions.configure<ShadowExtension> {\n                component(this@create)\n            }\n        }\n    }\n}\nconfigurePublications()\n"
  },
  {
    "path": "diktat-cli/src/main/kotlin/com/saveourtool/diktat/DiktatMain.kt",
    "content": "/**\n * The file contains main method\n */\n\npackage com.saveourtool.diktat\n\nimport com.saveourtool.diktat.api.DiktatProcessorListener\nimport com.saveourtool.diktat.cli.DiktatMode\nimport com.saveourtool.diktat.cli.DiktatProperties\n\nimport io.github.oshai.kotlinlogging.KotlinLogging\n\nimport java.nio.file.Path\nimport java.nio.file.Paths\n\nimport kotlin.io.path.absolutePathString\nimport kotlin.system.exitProcess\n\nprivate val log = KotlinLogging.logger { }\n\nprivate val loggingListener = object : DiktatProcessorListener {\n    override fun before(file: Path) {\n        log.debug {\n            \"Start processing the file: $file\"\n        }\n    }\n}\n\nfun main(args: Array<String>) {\n    val properties = DiktatProperties.parse(diktatReporterFactory, args)\n    properties.configureLogger()\n\n    log.debug {\n        \"Loading diktatRuleSet using config ${properties.config}\"\n    }\n    val currentFolder = Paths.get(\".\").toAbsolutePath().normalize()\n    val diktatRunnerArguments = properties.toRunnerArguments(\n        sourceRootDir = currentFolder,\n        loggingListener = loggingListener,\n    )\n\n    val diktatRunner = diktatRunnerFactory(diktatRunnerArguments)\n    val unfixedErrors = when (properties.mode) {\n        DiktatMode.CHECK -> diktatRunner.checkAll(diktatRunnerArguments)\n        DiktatMode.FIX -> diktatRunner.fixAll(diktatRunnerArguments) { updatedFile ->\n            log.warn {\n                \"Original and formatted content differ, writing to ${updatedFile.absolutePathString()}...\"\n            }\n        }\n    }\n    if (unfixedErrors > 0) {\n        exitProcess(1)\n    }\n}\n"
  },
  {
    "path": "diktat-cli/src/main/kotlin/com/saveourtool/diktat/cli/DiktatMode.kt",
    "content": "package com.saveourtool.diktat.cli\n\nimport kotlinx.serialization.SerialName\nimport kotlinx.serialization.Serializable\n\n/**\n * Mode of `diktat`\n */\n@Serializable\nenum class DiktatMode {\n    @SerialName(\"check\")\n    CHECK,\n    @SerialName(\"fix\")\n    FIX,\n    ;\n}\n"
  },
  {
    "path": "diktat-cli/src/main/kotlin/com/saveourtool/diktat/cli/DiktatProperties.kt",
    "content": "package com.saveourtool.diktat.cli\n\nimport com.saveourtool.diktat.DIKTAT\nimport com.saveourtool.diktat.DIKTAT_ANALYSIS_CONF\nimport com.saveourtool.diktat.DiktatRunnerArguments\nimport com.saveourtool.diktat.ENGINE_INFO\nimport com.saveourtool.diktat.api.DiktatProcessorListener\nimport com.saveourtool.diktat.api.DiktatReporterCreationArguments\nimport com.saveourtool.diktat.api.DiktatReporterFactory\nimport com.saveourtool.diktat.api.DiktatReporterType\nimport com.saveourtool.diktat.util.isKotlinCodeOrScript\nimport com.saveourtool.diktat.util.listFiles\n\nimport generated.DIKTAT_VERSION\nimport org.apache.logging.log4j.LogManager\nimport org.apache.logging.log4j.core.LoggerContext\nimport org.slf4j.event.Level\n\nimport java.io.OutputStream\nimport java.nio.file.Path\nimport java.nio.file.Paths\n\nimport kotlin.io.path.absolute\nimport kotlin.io.path.createDirectories\nimport kotlin.io.path.exists\nimport kotlin.io.path.inputStream\nimport kotlin.io.path.outputStream\nimport kotlin.system.exitProcess\nimport kotlinx.cli.ArgParser\nimport kotlinx.cli.ArgType\nimport kotlinx.cli.default\nimport kotlinx.cli.vararg\n\n/**\n * @param reporterType\n * @param output\n * @param groupByFileInStdout\n * @param colorNameInStdout\n * @param logLevel\n * @property config path to `diktat-analysis.yml`\n * @property mode mode of `diktat`\n * @property patterns\n */\ndata class DiktatProperties(\n    val config: String?,\n    val mode: DiktatMode,\n    private val reporterType: DiktatReporterType?,\n    private val output: String?,\n    private val groupByFileInStdout: Boolean?,\n    private val colorNameInStdout: String?,\n    private val logLevel: Level,\n    val patterns: List<String>,\n) {\n    /**\n     * Configure logger level using [logLevel]\n     */\n    fun configureLogger() {\n        // set log level\n        LogManager.getContext(false)\n            .let { it as LoggerContext }\n            .also { ctx ->\n                ctx.configuration.rootLogger.level = when (logLevel) {\n                    Level.ERROR -> org.apache.logging.log4j.Level.ERROR\n                    Level.WARN -> org.apache.logging.log4j.Level.WARN\n                    Level.INFO -> org.apache.logging.log4j.Level.INFO\n                    Level.DEBUG -> org.apache.logging.log4j.Level.DEBUG\n                    Level.TRACE -> org.apache.logging.log4j.Level.TRACE\n                }\n            }\n            .updateLoggers()\n    }\n\n    /**\n     * @param sourceRootDir\n     * @param loggingListener\n     * @return [DiktatRunnerArguments] created from [DiktatProperties]\n     */\n    fun toRunnerArguments(\n        sourceRootDir: Path,\n        loggingListener: DiktatProcessorListener,\n    ): DiktatRunnerArguments {\n        val stdoutReporterCreationArguments = DiktatReporterCreationArguments(\n            reporterType = DiktatReporterType.PLAIN,\n            outputStream = null,\n            sourceRootDir = sourceRootDir,\n            groupByFileInPlain = groupByFileInStdout,\n            colorNameInPlain = colorNameInStdout,\n        )\n        val reporterCreationArguments = reporterType?.let {\n            DiktatReporterCreationArguments(\n                reporterType = it,\n                outputStream = getRequiredReporterOutput(),\n                sourceRootDir = sourceRootDir,\n            )\n        }\n        return DiktatRunnerArguments(\n            configInputStream = config?.let { Paths.get(it).inputStream() } ?: Paths.get(DIKTAT_ANALYSIS_CONF).takeIf { it.exists() }?.inputStream(),\n            sourceRootDir = sourceRootDir,\n            files = getFiles(sourceRootDir),\n            baselineFile = null,\n            reporterArgsList = listOfNotNull(stdoutReporterCreationArguments, reporterCreationArguments),\n            loggingListener = loggingListener,\n        )\n    }\n\n    private fun getFiles(sourceRootDir: Path): Collection<Path> = sourceRootDir.listFiles(patterns = patterns.toTypedArray())\n        .filter { file -> file.isKotlinCodeOrScript() }\n        .toList()\n\n    private fun getRequiredReporterOutput(): OutputStream = output\n        ?.let { Paths.get(it).absolute() }\n        ?.also { it.parent.createDirectories() }\n        ?.outputStream()\n        ?: throw IllegalArgumentException(\"A file for the reporter output is not provided\")\n\n    companion object {\n        /**\n         * @param diktatReporterFactory\n         * @param args cli arguments\n         * @return parsed [DiktatProperties]\n         */\n        @Suppress(\n            \"LongMethod\",\n            \"TOO_LONG_FUNCTION\"\n        )\n        fun parse(\n            diktatReporterFactory: DiktatReporterFactory,\n            args: Array<String>,\n        ): DiktatProperties {\n            val parser = ArgParser(DIKTAT)\n            val config: String? by parser.config()\n            val mode: DiktatMode by parser.diktatMode()\n            val reporterType: DiktatReporterType? by parser.reporterType()\n            val output: String? by parser.output()\n            val groupByFile: Boolean? by parser.groupByFile()\n            val colorName: String? by parser.colorName(diktatReporterFactory)\n            val logLevel: Level by parser.logLevel()\n            val patterns: List<String> by parser.argument(\n                type = ArgType.String,\n                description = \"A list of files to process by diktat\"\n            ).vararg()\n\n            parser.addOptionAndShowTextWithExit(\n                fullName = \"version\",\n                shortName = \"V\",\n                description = \"Output version information and exit.\",\n                args = args,\n            ) {\n                \"\"\"\n                    Diktat: $DIKTAT_VERSION\n                    $ENGINE_INFO\n                \"\"\".trimIndent()\n            }\n            parser.addOptionAndShowTextWithExit(\n                fullName = \"license\",\n                shortName = null,\n                description = \"Display the license and exit.\",\n                args = args,\n            ) {\n                val resourceName = \"META-INF/diktat/LICENSE\"\n                DiktatProperties::class.java\n                    .classLoader\n                    .getResource(resourceName)\n                    ?.readText()\n                    ?: error(\"Resource $resourceName not found\")\n            }\n\n            parser.parse(args)\n            return DiktatProperties(\n                config = config,\n                mode = mode,\n                reporterType = reporterType,\n                output = output,\n                groupByFileInStdout = groupByFile,\n                colorNameInStdout = colorName,\n                logLevel = logLevel,\n                patterns = patterns,\n            )\n        }\n\n        /**\n         * @return a single and optional [String] for location of config as parsed cli arg\n         */\n        private fun ArgParser.config() = option(\n            type = ArgType.String,\n            fullName = \"config\",\n            shortName = \"c\",\n            description = \"Specify the location of the YAML configuration file. By default, $DIKTAT_ANALYSIS_CONF in the current directory is used.\",\n        )\n\n        /**\n         * @return a single type of [DiktatMode] as parsed cli arg. [DiktatMode.CHECK] is default value\n         */\n        private fun ArgParser.diktatMode() = option(\n            type = ArgType.Choice<DiktatMode>(),\n            fullName = \"mode\",\n            shortName = \"m\",\n            description = \"Mode of `diktat` controls that `diktat` fixes or only finds any deviations from the code style.\"\n        ).default(DiktatMode.CHECK)\n\n        /**\n         * @return a single and optional type of [DiktatReporterType] as parsed cli arg\n         */\n        private fun ArgParser.reporterType() = option(\n            type = ArgType.Choice<DiktatReporterType>(),\n            fullName = \"reporter\",\n            shortName = \"r\",\n            description = \"The reporter to use to log errors to output.\"\n        )\n\n        /**\n         * @return a single and optional [String] for output as parsed cli arg\n         */\n        private fun ArgParser.output() = option(\n            type = ArgType.String,\n            fullName = \"output\",\n            shortName = \"o\",\n            description = \"Redirect the reporter output to a file. Must be provided when the reporter is provided.\",\n        )\n\n        /**\n         * @return an optional flag to enable a grouping errors by files\n         */\n        private fun ArgParser.groupByFile() = option(\n            type = ArgType.Boolean,\n            fullName = \"group-by-file\",\n            shortName = null,\n            description = \"A flag to group found errors by files.\"\n        )\n\n        /**\n         * @param diktatReporterFactory\n         * @return a single and optional color name as parsed cli args\n         */\n        private fun ArgParser.colorName(diktatReporterFactory: DiktatReporterFactory) = option(\n            type = ArgType.Choice(\n                choices = diktatReporterFactory.colorNamesInPlain.toList(),\n                toVariant = { it },\n                variantToString = { it },\n            ),\n            fullName = \"color\",\n            shortName = null,\n            description = \"Colorize the output.\",\n        )\n\n        /**\n         * @return a single log leve as parser cli args. [Level.INFO] is default value\n         */\n        private fun ArgParser.logLevel() = option(\n            type = ArgType.Choice<Level>(),\n            fullName = \"log-level\",\n            shortName = \"l\",\n            description = \"Control the log level.\",\n        ).default(Level.INFO)\n\n        private fun ArgParser.addOptionAndShowTextWithExit(\n            fullName: String,\n            shortName: String?,\n            description: String,\n            args: Array<String>,\n            contentSupplier: () -> String\n        ) {\n            // add here to print in help\n            option(\n                type = ArgType.Boolean,\n                fullName = fullName,\n                shortName = shortName,\n                description = description\n            )\n            if (args.contains(\"--$fullName\") || shortName?.let { args.contains(\"-$it\") } == true) {\n                @Suppress(\"DEBUG_PRINT\", \"ForbiddenMethodCall\")\n                println(contentSupplier())\n                exitProcess(0)\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "diktat-cli/src/main/kotlin/com/saveourtool/diktat/util/CliUtils.kt",
    "content": "/**\n * This class contains util methods to operate with java.nio.file.Path for CLI\n */\n\npackage com.saveourtool.diktat.util\n\nimport java.io.File\nimport java.nio.file.FileSystems\nimport java.nio.file.InvalidPathException\nimport java.nio.file.Path\nimport java.nio.file.Paths\nimport kotlin.io.path.ExperimentalPathApi\nimport kotlin.io.path.Path\nimport kotlin.io.path.absolutePathString\nimport kotlin.io.path.exists\nimport kotlin.io.path.walk\n\nprivate const val NEGATIVE_PREFIX_PATTERN = \"!\"\nprivate const val PARENT_DIRECTORY_PREFIX = 3\nprivate const val PARENT_DIRECTORY_UNIX = \"../\"\nprivate const val PARENT_DIRECTORY_WINDOWS = \"..\\\\\"\n\n// all roots\nprivate val roots: Set<String> = FileSystems.getDefault()\n    .rootDirectories\n    .asSequence()\n    .map { it.absolutePathString() }\n    .toSet()\n\n/**\n * Lists all files in [this] directory based on [patterns]\n *\n * @param patterns a path to a file or a directory (all files from this directory will be returned) or an [Ant-style path pattern](https://ant.apache.org/manual/dirtasks.html#patterns)\n * @return [Sequence] of files as [Path] matched to provided [patterns]\n */\nfun Path.listFiles(\n    vararg patterns: String,\n): Sequence<Path> {\n    val (includePatterns, excludePatterns) = patterns.partition { !it.startsWith(NEGATIVE_PREFIX_PATTERN) }\n    val exclude by lazy {\n        doListFiles(excludePatterns.map { it.removePrefix(NEGATIVE_PREFIX_PATTERN) })\n            .toSet()\n    }\n    return doListFiles(includePatterns).filterNot { exclude.contains(it) }\n}\n\n@OptIn(ExperimentalPathApi::class)\nprivate fun Path.doListFiles(patterns: List<String>): Sequence<Path> = patterns\n    .asSequence()\n    .flatMap { pattern ->\n        tryToResolveIfExists(pattern, this)?.walk() ?: walkByGlob(pattern)\n    }\n    .map { it.normalize() }\n    .map { it.toAbsolutePath() }\n    .distinct()\n\n/**\n * Create a matcher and return a filter that uses it.\n *\n * @param glob glob pattern to filter files\n * @return a sequence of files which matches to [glob]\n */\n@OptIn(ExperimentalPathApi::class)\nprivate fun Path.walkByGlob(glob: String): Sequence<Path> = if (glob.startsWith(PARENT_DIRECTORY_UNIX) || glob.startsWith(PARENT_DIRECTORY_WINDOWS)) {\n    parent?.walkByGlob(glob.substring(PARENT_DIRECTORY_PREFIX)) ?: emptySequence()\n} else {\n    getAbsoluteGlobAndRoot(glob, this)\n        .let { (absoluteGlob, root) ->\n            absoluteGlob\n                .replace(\"([^\\\\\\\\])\\\\\\\\([^\\\\\\\\])\".toRegex(), \"$1\\\\\\\\\\\\\\\\$2\")  // encode Windows separators\n                .let { root.fileSystem.getPathMatcher(\"glob:$it\") }\n                .let { matcher ->\n                    root.walk().filter { matcher.matches(it) }\n                }\n        }\n}\n\nprivate fun String.findRoot(): Path = substring(0, indexOf('*'))\n    .let { withoutAsterisks ->\n        withoutAsterisks.substring(0, withoutAsterisks.lastIndexOfAny(charArrayOf('\\\\', '/')))\n    }\n    .let { Path(it) }\n\n/**\n * @param candidate\n * @param currentDirectory\n * @return path or null if path is invalid or doesn't exist\n */\nprivate fun tryToResolveIfExists(candidate: String, currentDirectory: Path): Path? = try {\n    Paths.get(candidate).takeIf { it.exists() }\n        ?: currentDirectory.resolve(candidate).takeIf { it.exists() }\n} catch (e: InvalidPathException) {\n    null\n}\n\nprivate fun getAbsoluteGlobAndRoot(glob: String, currentFolder: Path): Pair<String, Path> = when {\n    glob.startsWith(\"**\") -> glob to currentFolder\n    roots.any { glob.startsWith(it, true) } -> glob to glob.findRoot()\n    else -> \"${currentFolder.absolutePathString()}${File.separatorChar}$glob\" to currentFolder\n}\n"
  },
  {
    "path": "diktat-cli/src/main/script/diktat.cmd",
    "content": "@echo off\n\nrem\nrem diKTat command-line client for Windows\nrem\nrem Uses Git Bash, so requires Git to be installed.\nrem\n\nset \"git_install_location=%ProgramFiles%\\Git\"\nset \"git_url=https://github.com/git-for-windows/git/releases/latest\"\n\nif exist \"%git_install_location%\" (\n\tsetlocal\n\tset \"PATH=%git_install_location%\\usr\\bin;%PATH%\"\n\tfor /f \"usebackq tokens=*\" %%p in (`cygpath \"%~dpn0\"`) do bash --noprofile --norc %%p %*\n) else (\n\techo Expecting Git for Windows at %git_install_location%; please install it from %git_url%\n\tstart %git_url%\n)\n"
  },
  {
    "path": "diktat-cli/src/main/script/header-diktat.sh",
    "content": "#!/usr/bin/env bash\n#\n# vim:ai et sw=4 si sta ts=4:\n#\n# External variables used:\n#\n# - JAVA_HOME\n# - GITHUB_ACTIONS\n\n# Bash strict mode,\n# see http://redsymbol.net/articles/unofficial-bash-strict-mode/.\nset -euo pipefail\nIFS=$'\\n'\n\nfunction error() {\n    local message\n    message=\"$*\"\n\n    if [[ \"${GITHUB_ACTIONS:=false}\" == 'true' ]]\n    then\n        # Echoing to GitHub.\n        echo \"::error::${message}\"\n    elif [[ -t 1 ]]\n    then\n        # Echoing to a terminal.\n        echo -e \"\\e[1m$(basename \"$0\"): \\e[31merror:\\e[0m ${message}\" >&2\n    else\n        # Echoing to a pipe.\n        echo \"$(basename \"$0\"): error: ${message}\" >&2\n    fi\n}\n\n# Exit codes.\n# The code of 1 is returned by ktlint in the event of failure.\ndeclare -ir ERROR_JAVA_NOT_FOUND=2\ndeclare -ir ERROR_INCOMPATIBLE_BASH_VERSION=3\n\nif (( BASH_VERSINFO[0] < 4 ))\nthen\n    error \"bash version ${BASH_VERSION} is too old, version 4+ is required\"\n    exit ${ERROR_INCOMPATIBLE_BASH_VERSION}\nfi\n\nJAVA_ARGS=()\nDIKTAT_JAR=\"$0\"\n\n# Locates Java, preferring JAVA_HOME.\n#\n# The 1st variable expansion prevents the \"unbound variable\" error if JAVA_HOME\n# is unset.\nfunction find_java() {\n    if [[ -n \"${JAVA_HOME:=}\" ]]\n    then\n        case \"$(uname -s)\" in\n            'MINGW32_NT-'* | 'MINGW64_NT-'* | 'MSYS_NT-'* )\n                JAVA_HOME=\"$(cygpath \"${JAVA_HOME}\")\"\n                ;;\n        esac\n\n        JAVA=\"${JAVA_HOME}/bin/java\"\n        # Update the PATH, just in case\n        export PATH=\"${JAVA_HOME}/bin:${PATH}\"\n    elif [[ -x \"$(which java 2>/dev/null)\" ]]\n    then\n        JAVA=\"$(which java 2>/dev/null)\"\n    else\n        error 'Java is not found'\n        exit ${ERROR_JAVA_NOT_FOUND}\n    fi\n}\n\n# On Windows, converts a UNIX path to Windows. Should be invoked before a path\n# is passed to any of the Windows-native tools (e.g.: `java`).\n#\n# On UNIX, just returns the 1st argument.\nfunction native_path() {\n    case \"$(uname -s)\" in\n        'MINGW32_NT-'* | 'MINGW64_NT-'* | 'MSYS_NT-'* )\n            cygpath --windows \"$1\"\n            ;;\n        *)\n            echo \"$1\"\n            ;;\n    esac\n}\n\nfind_java\n\nJAVA_ARGS+=('-Xmx512m')\nJAVA_ARGS+=('-jar' \"$(native_path \"${DIKTAT_JAR}\")\")\n\nexec \"${JAVA}\" \"${JAVA_ARGS[@]}\" \"$@\"\n"
  },
  {
    "path": "diktat-cli/src/test/kotlin/com/saveourtool/diktat/smoke/DiktatCliTest.kt",
    "content": "package com.saveourtool.diktat.smoke\n\nimport com.saveourtool.diktat.test.framework.util.checkForkedJavaHome\nimport com.saveourtool.diktat.test.framework.util.deleteIfExistsSilently\nimport com.saveourtool.diktat.test.framework.util.inheritJavaHome\nimport com.saveourtool.diktat.test.framework.util.isWindows\nimport com.saveourtool.diktat.test.framework.util.temporaryDirectory\nimport io.github.oshai.kotlinlogging.KotlinLogging\nimport org.assertj.core.api.SoftAssertions.assertSoftly\nimport org.junit.jupiter.api.BeforeAll\nimport org.junit.jupiter.api.Test\nimport org.junit.jupiter.api.io.TempDir\nimport java.nio.file.Path\nimport java.nio.file.Paths\nimport kotlin.io.path.ExperimentalPathApi\nimport kotlin.io.path.PathWalkOption\nimport kotlin.io.path.absolutePathString\nimport kotlin.io.path.copyTo\nimport kotlin.io.path.createDirectories\nimport kotlin.io.path.div\nimport kotlin.io.path.isDirectory\nimport kotlin.io.path.readText\nimport kotlin.io.path.walk\n\nclass DiktatCliTest {\n\n    @Test\n    fun `Run diKTat from cli`() {\n        cliTest(\"examples/maven/src/main/kotlin/Test.kt\")\n    }\n\n    @Test\n    fun `Run diKTat from cli (absolute paths)`() {\n        cliTest(tempDir.resolve(\"examples/maven/src/main/kotlin/Test.kt\").absolutePathString())\n    }\n\n    @Test\n    fun `Run diKTat from cli (glob paths, 1 of 4)`() {\n        cliTest(\"examples/maven/src/main/kotlin/*.kt\")\n    }\n\n    @Test\n    fun `Run diKTat from cli (glob paths, 2 of 4)`() {\n        cliTest(\"examples/**/main/kotlin/*.kt\")\n    }\n\n    @Test\n    fun `Run diKTat from cli (glob paths, 3 of 4)`() {\n        cliTest(\"examples/**/*.kt\")\n    }\n\n    @Test\n    fun `Run diKTat from cli (glob paths, 4 of 4)`() {\n        cliTest(\"**/*.kt\")\n    }\n\n    @Suppress(\"TOO_LONG_FUNCTION\")\n    private fun cliTest(\n        vararg cliArgs: String,\n    ) {\n        assertSoftly { softly ->\n            val diktatCliLog = (tempDir / \"log.txt\").apply {\n                parent.createDirectories()\n                deleteIfExistsSilently()\n            }\n\n            val processBuilder = createProcessBuilderWithCmd(*cliArgs).apply {\n                redirectErrorStream(true)\n                redirectOutput(ProcessBuilder.Redirect.appendTo(diktatCliLog.toFile()))\n\n                /*\n                 * Inherit JAVA_HOME for the child process.\n                 */\n                inheritJavaHome()\n\n                temporaryDirectory(tempDir / \".tmp\")\n            }\n\n            val diktatCliProcess = processBuilder.start()\n            val exitCode = diktatCliProcess.waitFor()\n            softly.assertThat(exitCode).describedAs(\"The exit code of Diktat CLI\").isOne\n\n            softly.assertThat(diktatCliLog).isRegularFile\n\n            val diktatCliOutput = diktatCliLog.readText()\n\n            val commandLine = processBuilder.command().joinToString(separator = \" \")\n            softly.assertThat(diktatCliOutput)\n                .describedAs(\"The output of \\\"$commandLine\\\"\")\n                .isNotEmpty\n                .contains(\"[VARIABLE_NAME_INCORRECT_FORMAT]\")\n                .doesNotContain(\"WARNING:\")\n        }\n    }\n\n    private fun createProcessBuilderWithCmd(vararg cliArgs: String): ProcessBuilder {\n        return when {\n            System.getProperty(\"os.name\").isWindows() -> arrayOf(*javaArgs, DIKTAT_CLI_JAR, *defaultArgs, *cliArgs)\n            else -> arrayOf(\"sh\", \"-c\", arrayOf(*javaArgs, DIKTAT_CLI_JAR, *defaultArgs, *cliArgs).joinToString(\" \"))\n        }.let { args -> ProcessBuilder(*args).directory(tempDir.toFile()) }\n    }\n\n    companion object {\n        private val logger = KotlinLogging.logger {}\n\n        private val javaArgs = arrayOf(\"java\", \"-showversion\", \"-jar\")\n        private val defaultArgs = arrayOf(\"--log-level\", \"debug\")\n\n        @JvmStatic\n        @TempDir\n        internal var tempDir: Path = Paths.get(\"/invalid\")\n\n        @BeforeAll\n        @JvmStatic\n        @OptIn(ExperimentalPathApi::class)\n        internal fun beforeAll() {\n            assertSoftly { softly ->\n                checkForkedJavaHome()\n\n                logger.info {\n                    \"The temp directory for the test is $tempDir.\"\n                }\n                val sourceDirectory = Paths.get(\"../examples\")\n                val targetDirectory = (tempDir / \"examples\").also {\n                    it.createDirectories()\n                }\n                sourceDirectory.walk(PathWalkOption.INCLUDE_DIRECTORIES).forEach { file ->\n                    if (file.isDirectory()) {\n                        targetDirectory.resolve(sourceDirectory.relativize(file)).createDirectories()\n                    } else {\n                        val dest = targetDirectory.resolve(sourceDirectory.relativize(file))\n                        file.copyTo(dest)\n                    }\n                }\n                copyDiktatCli(softly, tempDir / DIKTAT_CLI_JAR)\n\n                val defaultConfigFile = Paths.get(\"../diktat-analysis.yml\")\n                softly.assertThat(defaultConfigFile)\n                    .describedAs(\"Default config file for diktat\")\n                    .isRegularFile\n                defaultConfigFile.copyTo(tempDir / \"diktat-analysis.yml\", overwrite = true)\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "diktat-cli/src/test/kotlin/com/saveourtool/diktat/smoke/DiktatSaveSmokeTest.kt",
    "content": "package com.saveourtool.diktat.smoke\n\nimport com.saveourtool.diktat.api.DiktatError\nimport com.saveourtool.diktat.test.framework.processing.TestComparatorUnit\nimport com.saveourtool.diktat.test.framework.util.checkForkedJavaHome\nimport com.saveourtool.diktat.test.framework.util.deleteIfExistsSilently\nimport com.saveourtool.diktat.test.framework.util.inheritJavaHome\nimport com.saveourtool.diktat.test.framework.util.isWindows\nimport com.saveourtool.diktat.test.framework.util.temporaryDirectory\n\nimport io.github.oshai.kotlinlogging.KotlinLogging\nimport org.assertj.core.api.Assertions.fail\nimport org.assertj.core.api.SoftAssertions.assertSoftly\nimport org.junit.jupiter.api.BeforeAll\nimport org.junit.jupiter.api.condition.DisabledOnOs\nimport org.junit.jupiter.api.condition.OS\n\nimport java.net.URL\nimport java.nio.file.Path\nimport kotlin.io.path.absolute\nimport kotlin.io.path.copyTo\nimport kotlin.io.path.createDirectories\nimport kotlin.io.path.div\nimport kotlin.io.path.readText\n\n@DisabledOnOs(OS.MAC)\nclass DiktatSaveSmokeTest : DiktatSmokeTestBase() {\n    override fun fixAndCompare(\n        config: Path,\n        expected: String,\n        test: String,\n    ) {\n        saveSmokeTest(config, test)\n    }\n\n    // do nothing, we can't check unfixed lint errors here\n    override fun assertUnfixedLintErrors(diktatErrorConsumer: (List<DiktatError>) -> Unit) = Unit\n\n    /**\n     * @param testPath path to file with code that will be transformed by formatter, loaded by [TestComparatorUnit.resourceReader]\n     * @param configFilePath path of diktat-analysis file\n     */\n    @Suppress(\"TOO_LONG_FUNCTION\")\n    private fun saveSmokeTest(\n        configFilePath: Path,\n        testPath: String\n    ) {\n        assertSoftly { softly ->\n            softly.assertThat(configFilePath).isRegularFile\n\n            val configFile = (baseDirectoryPath / \"diktat-analysis.yml\").apply {\n                parent.createDirectories()\n            }\n            val saveLog = (baseDirectoryPath / \"tmpSave.txt\").apply {\n                parent.createDirectories()\n                deleteIfExistsSilently()\n            }\n\n            configFilePath.copyTo(configFile, overwrite = true)\n\n            val processBuilder = createProcessBuilderWithCmd(testPath).apply {\n                redirectErrorStream(true)\n                redirectOutput(ProcessBuilder.Redirect.appendTo(saveLog.toFile()))\n\n                /*\n                 * Inherit JAVA_HOME for the child process.\n                 */\n                inheritJavaHome()\n\n                temporaryDirectory(baseDirectoryPath / TEMP_DIRECTORY)\n            }\n\n            val saveProcess = processBuilder.start()\n            val saveExitCode = saveProcess.waitFor()\n            softly.assertThat(saveExitCode).describedAs(\"The exit code of SAVE\").isZero\n\n            softly.assertThat(saveLog).isRegularFile\n\n            val saveOutput = saveLog.readText()\n\n            val saveCommandLine = processBuilder.command().joinToString(separator = \" \")\n            softly.assertThat(saveOutput)\n                .describedAs(\"The output of \\\"$saveCommandLine\\\"\")\n                .isNotEmpty\n                .contains(\"SUCCESS\")\n        }\n    }\n\n    /**\n     * @param testPath path to file with code that will be transformed by formatter, loaded by [TestComparatorUnit.resourceReader]\n     * @return ProcessBuilder\n     */\n    private fun createProcessBuilderWithCmd(testPath: String): ProcessBuilder {\n        val savePath = baseDirectoryPath.resolve(getSaveForCurrentOs()).toString()\n        val saveArgs = arrayOf(\n            baseDirectoryPath.resolve(\"src/main/kotlin\").toString(),\n            testPath,\n            \"--log\",\n            \"all\"\n        )\n\n        return when {\n            System.getProperty(\"os.name\").isWindows() -> arrayOf(savePath, *saveArgs)\n            else -> arrayOf(\"sh\", \"-c\", \"chmod 777 $savePath ; $savePath ${saveArgs.joinToString(\" \")}\")\n        }.let { args ->\n            ProcessBuilder(*args)\n        }\n    }\n\n    companion object {\n        private val logger = KotlinLogging.logger {}\n        private const val SAVE_VERSION: String = \"0.3.4\"\n        private const val TEMP_DIRECTORY = \".save-cli\"\n        private val baseDirectoryPath by lazy { tempDir.absolute() }\n\n        private fun getSaveForCurrentOs(): String {\n            val osName = System.getProperty(\"os.name\")\n\n            return when {\n                osName.startsWith(\"Linux\", ignoreCase = true) -> \"save-$SAVE_VERSION-linuxX64.kexe\"\n                osName.startsWith(\"Mac\", ignoreCase = true) -> \"save-$SAVE_VERSION-macosX64.kexe\"\n                osName.isWindows() -> \"save-$SAVE_VERSION-mingwX64.exe\"\n                else -> fail(\"SAVE doesn't support $osName (version ${System.getProperty(\"os.version\")})\")\n            }\n        }\n\n        private fun downloadFile(from: URL, to: Path) = downloadFile(from, to, baseDirectoryPath)\n\n        @BeforeAll\n        @JvmStatic\n        internal fun beforeAll() {\n            assertSoftly { softly ->\n                checkForkedJavaHome()\n\n                logger.info {\n                    \"The base directory for the smoke test is $baseDirectoryPath.\"\n                }\n\n                val diktat = baseDirectoryPath / DIKTAT_CLI_JAR\n                copyDiktatCli(softly, diktat)\n                val save = baseDirectoryPath / getSaveForCurrentOs()\n                downloadFile(URL(\"https://github.com/saveourtool/save-cli/releases/download/v$SAVE_VERSION/${getSaveForCurrentOs()}\"), save)\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "diktat-cli/src/test/kotlin/com/saveourtool/diktat/smoke/DiktatSmokeTest.kt",
    "content": "package com.saveourtool.diktat.smoke\n\nimport com.saveourtool.diktat.api.DiktatError\nimport com.saveourtool.diktat.ktlint.format\nimport com.saveourtool.diktat.ruleset.config.DiktatRuleConfigYamlReader\nimport com.saveourtool.diktat.ruleset.rules.DiktatRuleSetFactoryImpl\nimport com.saveourtool.diktat.test.framework.processing.TestComparatorUnit\nimport org.junit.jupiter.api.Assertions\nimport org.junit.jupiter.api.BeforeEach\nimport java.nio.file.Path\nimport kotlin.io.path.inputStream\n\n/**\n * Test for [DiktatRuleSetFactoryImpl] in autocorrect mode as a whole. All rules are applied to a file.\n * Note: ktlint uses initial text from a file to calculate line and column from offset. Because of that line/col of unfixed errors\n * may change after some changes to text or other rules.\n */\nclass DiktatSmokeTest : DiktatSmokeTestBase() {\n    private val unfixedLintErrors: MutableList<DiktatError> = mutableListOf()\n\n    override fun fixAndCompare(\n        config: Path,\n        expected: String,\n        test: String,\n    ) {\n        val result = getTestComparatorUnit(config)\n            .compareFilesFromResources(expected, test)\n        result.assertSuccessful()\n    }\n\n    @BeforeEach\n    internal fun setUp() {\n        unfixedLintErrors.clear()\n    }\n\n    override fun assertUnfixedLintErrors(diktatErrorConsumer: (List<DiktatError>) -> Unit) {\n        diktatErrorConsumer(unfixedLintErrors)\n    }\n\n    private fun getTestComparatorUnit(config: Path) = TestComparatorUnit(\n        resourceReader = { tempDir.resolve(\"src/main/kotlin\").resolve(it).normalize() },\n        function = { testFile ->\n            format(\n                ruleSetSupplier = {\n                    val diktatRuleConfigReader = DiktatRuleConfigYamlReader()\n                    val diktatRuleSetFactory = DiktatRuleSetFactoryImpl()\n                    diktatRuleSetFactory(diktatRuleConfigReader(config.inputStream()))\n                },\n                file = testFile,\n                cb = { lintError, _ -> unfixedLintErrors.add(lintError) },\n            )\n        },\n    )\n}\n"
  },
  {
    "path": "diktat-cli/src/test/kotlin/com/saveourtool/diktat/smoke/DiktatSmokeTestBase.kt",
    "content": "@file:Suppress(\n    \"MISSING_KDOC_CLASS_ELEMENTS\",\n    \"MISSING_KDOC_ON_FUNCTION\",\n    \"BACKTICKS_PROHIBITED\",\n)\n\npackage com.saveourtool.diktat.smoke\n\nimport com.saveourtool.diktat.api.DiktatError\nimport com.saveourtool.diktat.common.config.rules.DIKTAT_COMMON\nimport com.saveourtool.diktat.common.config.rules.DIKTAT_RULE_SET_ID\nimport com.saveourtool.diktat.common.config.rules.RulesConfig\nimport com.saveourtool.diktat.ruleset.config.DiktatRuleConfigYamlReader\nimport com.saveourtool.diktat.ruleset.constants.Warnings\nimport com.saveourtool.diktat.ruleset.constants.Warnings.EMPTY_BLOCK_STRUCTURE_ERROR\nimport com.saveourtool.diktat.ruleset.constants.Warnings.FILE_NAME_MATCH_CLASS\nimport com.saveourtool.diktat.ruleset.constants.Warnings.HEADER_MISSING_IN_NON_SINGLE_CLASS_FILE\nimport com.saveourtool.diktat.ruleset.constants.Warnings.KDOC_NO_EMPTY_TAGS\nimport com.saveourtool.diktat.ruleset.constants.Warnings.MISSING_KDOC_CLASS_ELEMENTS\nimport com.saveourtool.diktat.ruleset.constants.Warnings.MISSING_KDOC_ON_FUNCTION\nimport com.saveourtool.diktat.ruleset.constants.Warnings.MISSING_KDOC_TOP_LEVEL\nimport com.saveourtool.diktat.ruleset.constants.Warnings.WRONG_INDENTATION\nimport com.saveourtool.diktat.ruleset.constants.Warnings.WRONG_NEWLINES\nimport com.saveourtool.diktat.ruleset.rules.chapter1.FileNaming\nimport com.saveourtool.diktat.ruleset.rules.chapter2.comments.CommentsRule\nimport com.saveourtool.diktat.ruleset.rules.chapter2.comments.HeaderCommentRule\nimport com.saveourtool.diktat.ruleset.rules.chapter2.kdoc.KdocComments\nimport com.saveourtool.diktat.ruleset.rules.chapter2.kdoc.KdocFormatting\nimport com.saveourtool.diktat.ruleset.rules.chapter2.kdoc.KdocMethods\nimport com.saveourtool.diktat.ruleset.rules.chapter3.EmptyBlock\nimport com.saveourtool.diktat.ruleset.rules.chapter3.files.SemicolonsRule\nimport com.saveourtool.diktat.ruleset.rules.chapter6.classes.InlineClassesRule\nimport com.saveourtool.diktat.ruleset.utils.indentation.IndentationConfig\nimport com.saveourtool.diktat.ruleset.utils.indentation.IndentationConfig.Companion.EXTENDED_INDENT_AFTER_OPERATORS\nimport com.saveourtool.diktat.ruleset.utils.indentation.IndentationConfig.Companion.EXTENDED_INDENT_BEFORE_DOT\nimport com.saveourtool.diktat.ruleset.utils.indentation.IndentationConfig.Companion.EXTENDED_INDENT_FOR_EXPRESSION_BODIES\n\nimport com.charleskorn.kaml.Yaml\nimport com.charleskorn.kaml.YamlConfiguration\nimport generated.WarningNames\nimport org.assertj.core.api.Assertions.assertThat\nimport org.junit.jupiter.api.BeforeAll\nimport org.junit.jupiter.api.Tag\nimport org.junit.jupiter.api.Test\nimport org.junit.jupiter.api.Timeout\nimport org.junit.jupiter.api.io.TempDir\nimport java.nio.file.Path\nimport java.nio.file.Paths\n\nimport java.time.LocalDate\nimport java.util.concurrent.TimeUnit.SECONDS\nimport kotlin.io.path.ExperimentalPathApi\nimport kotlin.io.path.PathWalkOption\nimport kotlin.io.path.copyTo\nimport kotlin.io.path.createDirectories\nimport kotlin.io.path.createTempFile\nimport kotlin.io.path.inputStream\nimport kotlin.io.path.isDirectory\nimport kotlin.io.path.moveTo\nimport kotlin.io.path.name\nimport kotlin.io.path.toPath\nimport kotlin.io.path.walk\nimport kotlin.io.path.writeText\n\nimport kotlinx.serialization.builtins.ListSerializer\n\ntypealias RuleToConfig = Map<String, Map<String, String>>\n\n/**\n * Base class for smoke test classes\n */\nabstract class DiktatSmokeTestBase {\n    /**\n     * Disable some of the rules.\n     *\n     * @param rulesToDisable\n     * @param rulesToOverride\n     */\n    @Suppress(\"UnsafeCallOnNullableType\")\n    private fun prepareOverriddenRulesConfig(rulesToDisable: List<Warnings> = emptyList(), rulesToOverride: RuleToConfig = emptyMap()): Path {\n        val rulesConfig = DiktatRuleConfigYamlReader().invoke(Paths.get(DEFAULT_CONFIG_PATH).inputStream())\n            .toMutableList()\n            .also { rulesConfig ->\n                rulesToDisable.forEach { warning ->\n                    rulesConfig.removeIf { it.name == warning.name }\n                    rulesConfig.add(RulesConfig(warning.name, enabled = false, configuration = emptyMap()))\n                }\n                rulesToOverride.forEach { (warning, configuration) ->\n                    rulesConfig.removeIf { it.name == warning }\n                    rulesConfig.add(RulesConfig(warning, enabled = true, configuration = configuration))\n                }\n            }\n            .toList()\n        return createTempFile()\n            .also {\n                it.writeText(\n                    Yaml(configuration = YamlConfiguration(strictMode = true))\n                        .encodeToString(ListSerializer(RulesConfig.serializer()), rulesConfig)\n                )\n            }\n    }\n\n    @Test\n    @Tag(\"DiktatRuleSetProvider\")\n    @Timeout(TEST_TIMEOUT_SECONDS, unit = SECONDS)\n    fun `regression - should not fail if package is not set`() {\n        val configFilePath = prepareOverriddenRulesConfig(listOf(Warnings.PACKAGE_NAME_MISSING, Warnings.PACKAGE_NAME_INCORRECT_PATH,\n            Warnings.PACKAGE_NAME_INCORRECT_PREFIX))\n        fixAndCompare(configFilePath, \"DefaultPackageExpected.kt\", \"DefaultPackageTest.kt\")\n    }\n\n    @Test\n    @Tag(\"DiktatRuleSetProvider\")\n    @Timeout(TEST_TIMEOUT_SECONDS, unit = SECONDS)\n    fun `smoke test #8 - anonymous function`() {\n        fixAndCompare(prepareOverriddenRulesConfig(), \"Example8Expected.kt\", \"Example8Test.kt\")\n    }\n\n    @Test\n    @Tag(\"DiktatRuleSetProvider\")\n    @Timeout(TEST_TIMEOUT_SECONDS, unit = SECONDS)\n    fun `smoke test #7`() {\n        fixAndCompare(prepareOverriddenRulesConfig(), \"Example7Expected.kt\", \"Example7Test.kt\")\n    }\n\n    @Test\n    @Tag(\"DiktatRuleSetProvider\")\n    @Timeout(TEST_TIMEOUT_SECONDS, unit = SECONDS)\n    fun `smoke test #6`() {\n        val configFilePath = prepareOverriddenRulesConfig(\n            rulesToDisable = emptyList(),\n            rulesToOverride = mapOf(\n                WRONG_INDENTATION.name to mapOf(\n                    EXTENDED_INDENT_FOR_EXPRESSION_BODIES to \"true\",\n                    EXTENDED_INDENT_AFTER_OPERATORS to \"true\",\n                    EXTENDED_INDENT_BEFORE_DOT to \"true\",\n                )\n            )\n        )\n        fixAndCompare(configFilePath, \"Example6Expected.kt\", \"Example6Test.kt\")\n    }\n\n    @Test\n    @Tag(\"DiktatRuleSetProvider\")\n    @Timeout(TEST_TIMEOUT_SECONDS, unit = SECONDS)\n    fun `smoke test #5`() {\n        val configFilePath = prepareOverriddenRulesConfig(emptyList(),\n            mapOf(\n                Warnings.HEADER_MISSING_OR_WRONG_COPYRIGHT.name to mapOf(\n                    \"isCopyrightMandatory\" to \"true\",\n                    \"copyrightText\" to \"\"\"|Copyright 2018-${LocalDate.now().year} John Doe.\n                                    |    Licensed under the Apache License, Version 2.0 (the \"License\");\n                                    |    you may not use this file except in compliance with the License.\n                                    |    You may obtain a copy of the License at\n                                    |\n                                    |        http://www.apache.org/licenses/LICENSE-2.0\n                                \"\"\".trimMargin()\n                ),\n                DIKTAT_COMMON to mapOf(\n                    \"domainName\" to \"com.saveourtool.diktat\",\n                    \"kotlinVersion\" to \"1.3.7\"\n                )\n            )\n        )\n        fixAndCompare(configFilePath, \"Example5Expected.kt\", \"Example5Test.kt\")\n\n        assertUnfixedLintErrors { unfixedLintErrors ->\n            assertThat(unfixedLintErrors).let { errors ->\n                errors.doesNotContain(\n                    DiktatError(\n                        line = 1,\n                        col = 1,\n                        ruleId = \"diktat-ruleset:${CommentsRule.NAME_ID}\",\n                        detail = \"${Warnings.COMMENTED_OUT_CODE.warnText()} /*\"\n                    )\n                )\n                errors.contains(\n                    DiktatError(12, 1, \"diktat-ruleset:${InlineClassesRule.NAME_ID}\", \"${Warnings.INLINE_CLASS_CAN_BE_USED.warnText()} class Some\")\n                )\n            }\n        }\n    }\n\n    @Test\n    @Tag(\"DiktatRuleSetProvider\")\n    @Timeout(TEST_TIMEOUT_SECONDS, unit = SECONDS)\n    fun `smoke test #4`() {\n        fixAndCompare(prepareOverriddenRulesConfig(), \"Example4Expected.kt\", \"Example4Test.kt\")\n    }\n\n    @Test\n    @Tag(\"DiktatRuleSetProvider\")\n    @Timeout(TEST_TIMEOUT_SECONDS, unit = SECONDS)\n    fun `smoke test #3`() {\n        fixAndCompare(prepareOverriddenRulesConfig(), \"Example3Expected.kt\", \"Example3Test.kt\")\n    }\n\n    @Test\n    @Tag(\"DiktatRuleSetProvider\")\n    @Timeout(TEST_TIMEOUT_SECONDS, unit = SECONDS)\n    fun `regression - shouldn't throw exception in cases similar to #371`() {\n        fixAndCompare(prepareOverriddenRulesConfig(), \"Bug1Expected.kt\", \"Bug1Test.kt\")\n    }\n\n    @Test\n    @Tag(\"DiktatRuleSetProvider\")\n    @Timeout(TEST_TIMEOUT_SECONDS, unit = SECONDS)\n    fun `smoke test #2`() {\n        val configFilePath = prepareOverriddenRulesConfig(\n            rulesToDisable = emptyList(),\n            rulesToOverride = mapOf(\n                WRONG_INDENTATION.name to mapOf(\n                    EXTENDED_INDENT_AFTER_OPERATORS to \"true\",\n                    EXTENDED_INDENT_BEFORE_DOT to \"true\",\n                )\n            )\n        )\n        fixAndCompare(configFilePath, \"Example2Expected.kt\", \"Example2Test.kt\")\n        assertUnfixedLintErrors { unfixedLintErrors ->\n            assertThat(unfixedLintErrors).containsExactlyInAnyOrder(\n                DiktatError(1, 1, \"$DIKTAT_RULE_SET_ID:${HeaderCommentRule.NAME_ID}\",\n                    \"${HEADER_MISSING_IN_NON_SINGLE_CLASS_FILE.warnText()} there are 2 declared classes and/or objects\", false),\n                DiktatError(34, 3, \"$DIKTAT_RULE_SET_ID:${EmptyBlock.NAME_ID}\",\n                    \"${EMPTY_BLOCK_STRUCTURE_ERROR.warnText()} empty blocks are forbidden unless it is function with override keyword\", false),\n            )\n        }\n    }\n\n    @Test\n    @Tag(\"DiktatRuleSetProvider\")\n    @Timeout(TEST_TIMEOUT_SECONDS, unit = SECONDS)\n    fun `smoke test #1`() {\n        val configFilePath = prepareOverriddenRulesConfig(\n            rulesToDisable = emptyList(),\n            rulesToOverride = mapOf(\n                WRONG_INDENTATION.name to mapOf(\n                    EXTENDED_INDENT_AFTER_OPERATORS to \"true\",\n                    EXTENDED_INDENT_FOR_EXPRESSION_BODIES to \"true\",\n                )\n            )\n        )\n        fixAndCompare(configFilePath, \"Example1Expected.kt\", \"Example1Test.kt\")\n        assertUnfixedLintErrors { unfixedLintErrors ->\n            assertThat(unfixedLintErrors).containsExactlyInAnyOrder(\n                DiktatError(1, 1, \"$DIKTAT_RULE_SET_ID:${FileNaming.NAME_ID}\", \"${FILE_NAME_MATCH_CLASS.warnText()} Example1Test.kt vs Example\", false),\n                DiktatError(3, 1, \"$DIKTAT_RULE_SET_ID:${KdocComments.NAME_ID}\", \"${MISSING_KDOC_TOP_LEVEL.warnText()} Example\", false),\n                DiktatError(4, 5, \"$DIKTAT_RULE_SET_ID:${KdocComments.NAME_ID}\", \"${MISSING_KDOC_CLASS_ELEMENTS.warnText()} isValid\", false),\n                DiktatError(6, 5, \"$DIKTAT_RULE_SET_ID:${KdocComments.NAME_ID}\", \"${MISSING_KDOC_CLASS_ELEMENTS.warnText()} foo\", false),\n                DiktatError(8, 5, \"$DIKTAT_RULE_SET_ID:${KdocComments.NAME_ID}\", \"${MISSING_KDOC_CLASS_ELEMENTS.warnText()} foo\", false),\n                DiktatError(8, 5, \"$DIKTAT_RULE_SET_ID:${KdocMethods.NAME_ID}\", \"${MISSING_KDOC_ON_FUNCTION.warnText()} foo\", false),\n                DiktatError(8, 19, \"$DIKTAT_RULE_SET_ID:${EmptyBlock.NAME_ID}\",\n                    \"${EMPTY_BLOCK_STRUCTURE_ERROR.warnText()} empty blocks are forbidden unless it is function with override keyword\", false),\n                DiktatError(13, 8, \"$DIKTAT_RULE_SET_ID:${KdocFormatting.NAME_ID}\", \"${KDOC_NO_EMPTY_TAGS.warnText()} @return\", false),\n                DiktatError(19, 8, \"$DIKTAT_RULE_SET_ID:${KdocFormatting.NAME_ID}\", \"${KDOC_NO_EMPTY_TAGS.warnText()} @return\", false),\n                DiktatError(27, 8, \"$DIKTAT_RULE_SET_ID:${KdocFormatting.NAME_ID}\", \"${KDOC_NO_EMPTY_TAGS.warnText()} @return\", false),\n                DiktatError(36, 8, \"$DIKTAT_RULE_SET_ID:${KdocFormatting.NAME_ID}\", \"${KDOC_NO_EMPTY_TAGS.warnText()} @return\", false),\n            )\n        }\n    }\n\n    @Test\n    @Tag(\"DiktatRuleSetProvider\")\n    @Timeout(TEST_TIMEOUT_SECONDS, unit = SECONDS)\n    fun `smoke test with kts files #2`() {\n        fixAndCompare(prepareOverriddenRulesConfig(), \"script/SimpleRunInScriptExpected.kts\", \"script/SimpleRunInScriptTest.kts\")\n    }\n\n    @Test\n    @Tag(\"DiktatRuleSetProvider\")\n    @Timeout(TEST_TIMEOUT_SECONDS, unit = SECONDS)\n    fun `smoke test with kts files with package name`() {\n        fixAndCompare(prepareOverriddenRulesConfig(), \"script/PackageInScriptExpected.kts\", \"script/PackageInScriptTest.kts\")\n    }\n\n    @Test\n    @Tag(\"DiktatRuleSetProvider\")\n    @Timeout(TEST_TIMEOUT_SECONDS, unit = SECONDS)\n    fun `regression - should correctly handle tags with empty lines`() {\n        fixAndCompare(prepareOverriddenRulesConfig(), \"KdocFormattingMultilineTagsExpected.kt\", \"KdocFormattingMultilineTagsTest.kt\")\n    }\n\n    @Test\n    @Tag(\"DiktatRuleSetProvider\")\n    @Timeout(TEST_TIMEOUT_SECONDS, unit = SECONDS)\n    fun `regression - FP of local variables rule`() {\n        fixAndCompare(prepareOverriddenRulesConfig(), \"LocalVariableWithOffsetExpected.kt\", \"LocalVariableWithOffsetTest.kt\")\n    }\n\n    @Test\n    @Tag(\"DiktatRuleSetProvider\")\n    @Timeout(TEST_TIMEOUT_SECONDS, unit = SECONDS)\n    fun `fix can cause long line`() {\n        val configFilePath = prepareOverriddenRulesConfig(\n            rulesToDisable = emptyList(),\n            rulesToOverride = mapOf(\n                WRONG_INDENTATION.name to mapOf(\n                    EXTENDED_INDENT_AFTER_OPERATORS to \"false\",\n                )\n            )\n        )\n        fixAndCompare(configFilePath, \"ManyLineTransformInLongLineExpected.kt\", \"ManyLineTransformInLongLineTest.kt\")\n    }\n\n    @Test\n    @Tag(\"DiktatRuleSetProvider\")\n    fun `smoke test with multiplatform project layout`() {\n        fixAndCompare(\n            prepareOverriddenRulesConfig(),\n            \"../../jsMain/kotlin/com/saveourtool/diktat/scripts/ScriptExpected.kt\",\n            \"../../jsMain/kotlin/com/saveourtool/diktat/scripts/ScriptTest.kt\"\n        )\n    }\n\n    @Test\n    @Tag(\"DiktatRuleSetProvider\")\n    fun `smoke test with kts files`() {\n        val configFilePath = prepareOverriddenRulesConfig(\n            emptyList(),\n            mapOf(\n                WRONG_INDENTATION.name to mapOf(\n                    IndentationConfig.NEWLINE_AT_END to \"false\",\n                )\n            )\n        )  // so that trailing newline isn't checked, because it's incorrectly read in tests and we are comparing file with itself\n        // file name is `gradle_` so that IDE doesn't suggest to import gradle project\n        val tmpFilePath = \"../../../build.gradle.kts\"\n        fixAndCompare(configFilePath, tmpFilePath, tmpFilePath)\n        assertUnfixedLintErrors { unfixedLintErrors ->\n            assertThat(unfixedLintErrors).isEmpty()\n        }\n    }\n\n    @Test\n    @Tag(\"DiktatRuleSetProvider\")\n    fun `smoke test with gradle script plugin`() {\n        fixAndCompare(prepareOverriddenRulesConfig(), \"kotlin-library-expected.gradle.kts\", \"kotlin-library.gradle.kts\")\n        assertUnfixedLintErrors { unfixedLintErrors ->\n            assertThat(unfixedLintErrors).containsExactly(\n                DiktatError(\n                    2, 1, \"$DIKTAT_RULE_SET_ID:${CommentsRule.NAME_ID}\", \"[COMMENTED_OUT_CODE] you should not comment out code, \" +\n                            \"use VCS to save it in history and delete this block: import org.jetbrains.kotlin.gradle.dsl.jvm\", false\n                )\n            )\n        }\n    }\n\n    @Test\n    @Tag(\"DiktatRuleSetProvider\")\n    fun `disable chapters`() {\n        val configFilePath = prepareOverriddenRulesConfig(\n            emptyList(),\n            mapOf(\n                DIKTAT_COMMON to mapOf(\n                    \"domainName\" to \"com.saveourtool.diktat\",\n                    \"disabledChapters\" to \"Naming,3,4,5,Classes\"\n                )\n            )\n        )\n        fixAndCompare(configFilePath, \"Example1-2Expected.kt\", \"Example1-2Test.kt\")\n        assertUnfixedLintErrors { unfixedLintErrors ->\n            assertThat(unfixedLintErrors).containsExactlyInAnyOrder(\n                DiktatError(3, 1, \"$DIKTAT_RULE_SET_ID:${KdocComments.NAME_ID}\", \"${MISSING_KDOC_TOP_LEVEL.warnText()} example\", false),\n                DiktatError(3, 16, \"$DIKTAT_RULE_SET_ID:${KdocComments.NAME_ID}\", \"${MISSING_KDOC_CLASS_ELEMENTS.warnText()} isValid\", false),\n                DiktatError(6, 5, \"$DIKTAT_RULE_SET_ID:${KdocComments.NAME_ID}\", \"${MISSING_KDOC_CLASS_ELEMENTS.warnText()} foo\", false),\n                DiktatError(6, 5, \"$DIKTAT_RULE_SET_ID:${KdocMethods.NAME_ID}\", \"${MISSING_KDOC_ON_FUNCTION.warnText()} foo\", false),\n                DiktatError(8, 5, \"$DIKTAT_RULE_SET_ID:${KdocComments.NAME_ID}\", \"${MISSING_KDOC_CLASS_ELEMENTS.warnText()} foo\", false),\n                DiktatError(13, 4, \"$DIKTAT_RULE_SET_ID:${KdocFormatting.NAME_ID}\", \"${KDOC_NO_EMPTY_TAGS.warnText()} @return\", false),\n                DiktatError(20, 4, \"$DIKTAT_RULE_SET_ID:${KdocFormatting.NAME_ID}\", \"${KDOC_NO_EMPTY_TAGS.warnText()} @return\", false),\n                DiktatError(28, 4, \"$DIKTAT_RULE_SET_ID:${KdocFormatting.NAME_ID}\", \"${KDOC_NO_EMPTY_TAGS.warnText()} @return\", false),\n                DiktatError(37, 4, \"$DIKTAT_RULE_SET_ID:${KdocFormatting.NAME_ID}\", \"${KDOC_NO_EMPTY_TAGS.warnText()} @return\", false),\n            )\n        }\n    }\n\n    @Test\n    @Tag(\"DiktatRuleSetProvider\")\n    @Timeout(TEST_TIMEOUT_SECONDS, unit = SECONDS)\n    fun `regression - should not fail if file has unnecessary semicolons`() {\n        fixAndCompare(prepareOverriddenRulesConfig(), \"SemicolonsExpected.kt\", \"SemicolonsTest.kt\")\n    }\n\n    @Test\n    @Tag(\"DiktatRuleSetProvider\")\n    @Timeout(TEST_TIMEOUT_SECONDS, unit = SECONDS)\n    fun `should add newlines between interfaces`() {\n        fixAndCompare(prepareOverriddenRulesConfig(), \"NewlinesAfterInterfacesExpected.kt\", \"NewlinesAfterInterfacesTest.kt\")\n    }\n\n    abstract fun fixAndCompare(\n        config: Path,\n        expected: String,\n        test: String,\n    )\n\n    abstract fun assertUnfixedLintErrors(diktatErrorConsumer: (List<DiktatError>) -> Unit)\n\n    companion object {\n        private const val DEFAULT_CONFIG_PATH = \"../diktat-analysis.yml\"\n        private const val ROOT_RESOURCE_FILE_PATH = \"test/smoke\"\n        private const val TEST_TIMEOUT_SECONDS = 30L\n\n        @JvmStatic\n        @TempDir\n        internal var tempDir: Path = Paths.get(\"/invalid\")\n\n        @BeforeAll\n        @JvmStatic\n        @OptIn(ExperimentalPathApi::class)\n        internal fun createTmpFiles() {\n            val resourceFilePath = DiktatSmokeTestBase::class.java\n                .classLoader\n                .getResource(ROOT_RESOURCE_FILE_PATH)\n                .let { resource ->\n                    requireNotNull(resource) {\n                        \"$ROOT_RESOURCE_FILE_PATH not found\"\n                    }\n                }\n                .toURI()\n                .toPath()\n            resourceFilePath.walk(PathWalkOption.INCLUDE_DIRECTORIES).forEach { file ->\n                if (file.isDirectory()) {\n                    tempDir.resolve(resourceFilePath.relativize(file)).createDirectories()\n                } else {\n                    val dest = tempDir.resolve(resourceFilePath.relativize(file))\n                    file.copyTo(dest)\n                    when (file.name) {\n                        \"build.gradle.kts_\" -> dest.moveTo(dest.parent.resolve(\"build.gradle.kts\"))\n                        \"Example1Test.kt\" -> dest.copyTo(dest.parent.resolve(\"Example1-2Test.kt\"))\n                    }\n                }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "diktat-cli/src/test/kotlin/com/saveourtool/diktat/smoke/DiktatSmokeTestUtils.kt",
    "content": "@file:Suppress(\"HEADER_MISSING_IN_NON_SINGLE_CLASS_FILE\")\n\npackage com.saveourtool.diktat.smoke\n\nimport com.saveourtool.diktat.test.framework.util.retry\nimport io.github.oshai.kotlinlogging.KotlinLogging\nimport org.assertj.core.api.Assertions.fail\nimport org.assertj.core.api.SoftAssertions\nimport java.net.URL\nimport java.nio.file.Path\nimport kotlin.io.path.Path\nimport kotlin.io.path.copyTo\nimport kotlin.io.path.exists\nimport kotlin.io.path.listDirectoryEntries\nimport kotlin.io.path.outputStream\nimport kotlin.io.path.relativeToOrSelf\nimport kotlin.system.measureNanoTime\n\ninternal const val BUILD_DIRECTORY = \"build/libs\"\ninternal const val DIKTAT_CLI_JAR = \"diktat.jar\"\ninternal const val DIKTAT_CLI_JAR_GLOB = \"diktat-cli-*.jar\"\n\nprivate val logger = KotlinLogging.logger {}\n\n/**\n * Downloads the file from a remote URL, retrying if necessary.\n *\n * @param from the remote URL to download from.\n * @param to the target path.\n * @param baseDirectory the directory against which [to] should be relativized\n *   if it's absolute.\n */\n@Suppress(\"FLOAT_IN_ACCURATE_CALCULATIONS\")\ninternal fun downloadFile(\n    from: URL,\n    to: Path,\n    baseDirectory: Path,\n) {\n    logger.info {\n        \"Downloading $from to ${to.relativeToOrSelf(baseDirectory)}...\"\n    }\n\n    @Suppress(\"MAGIC_NUMBER\")\n    val attempts = 5\n\n    val lazyDefault: (Throwable) -> Unit = { error ->\n        fail(\"Failure downloading $from after $attempts attempt(s)\", error)\n    }\n\n    retry(attempts, lazyDefault = lazyDefault) {\n        from.openStream().use { source ->\n            to.outputStream().use { target ->\n                val bytesCopied: Long\n                val timeNanos = measureNanoTime {\n                    bytesCopied = source.copyTo(target)\n                }\n                logger.info {\n                    \"$bytesCopied byte(s) copied in ${timeNanos / 1000 / 1e3} ms.\"\n                }\n            }\n        }\n    }\n}\n\n/**\n * Copies the diktat-cli.jar with assertions\n *\n * @param softAssertions\n * @param to the target path.\n */\ninternal fun copyDiktatCli(\n    softAssertions: SoftAssertions,\n    to: Path\n) {\n    /*\n     * The fat JAR should reside in the same directory as `save*` and\n     * be named `diktat.jar`\n     * (see `diktat-cli/src/test/resources/test/smoke/save.toml`).\n     */\n    val buildDirectory = Path(BUILD_DIRECTORY)\n    softAssertions.assertThat(buildDirectory)\n        .isDirectory\n    val diktatFrom = buildDirectory\n        .takeIf(Path::exists)\n        ?.listDirectoryEntries(DIKTAT_CLI_JAR_GLOB)\n        ?.singleOrNull()\n    softAssertions.assertThat(diktatFrom)\n        .describedAs(diktatFrom?.toString() ?: \"$BUILD_DIRECTORY/$DIKTAT_CLI_JAR_GLOB\")\n        .isNotNull\n        .isRegularFile\n\n    diktatFrom?.copyTo(to, overwrite = true)\n}\n"
  },
  {
    "path": "diktat-cli/src/test/kotlin/com/saveourtool/diktat/util/CliUtilsKtTest.kt",
    "content": "package com.saveourtool.diktat.util\n\nimport org.assertj.core.api.Assertions\nimport org.junit.jupiter.api.BeforeAll\nimport org.junit.jupiter.api.Test\nimport org.junit.jupiter.api.condition.EnabledOnOs\nimport org.junit.jupiter.api.condition.OS\nimport org.junit.jupiter.api.io.TempDir\nimport java.io.File\nimport java.nio.file.Path\nimport java.nio.file.Paths\nimport kotlin.io.path.absolutePathString\nimport kotlin.io.path.createDirectory\nimport kotlin.io.path.createFile\nimport kotlin.io.path.writeText\n\nclass CliUtilsKtTest {\n    @Test\n    fun listByFilesWithLeadingAsterisks() {\n        Assertions.assertThat(tmpDir.listFiles(\"**/Test1.kt\").toList())\n            .containsExactlyInAnyOrder(\n                tmpDir.resolve(\"folder1\").resolve(\"subFolder11\").resolve(\"Test1.kt\"),\n                tmpDir.resolve(\"folder1\").resolve(\"subFolder12\").resolve(\"Test1.kt\"),\n                tmpDir.resolve(\"folder2\").resolve(\"Test1.kt\"),\n            )\n    }\n\n    @Test\n    fun listByFilesWithGlobalPath() {\n        Assertions.assertThat(tmpDir.listFiles(\"${tmpDir.absolutePathString()}${File.separator}**${File.separator}Test2.kt\").toList())\n            .containsExactlyInAnyOrder(\n                tmpDir.resolve(\"folder1\").resolve(\"subFolder11\").resolve(\"Test2.kt\"),\n                tmpDir.resolve(\"folder2\").resolve(\"Test2.kt\"),\n            )\n    }\n\n    @Test\n    fun listByFilesWithGlobalPattern() {\n        Assertions.assertThat(tmpDir.resolve(\"folder2\").listFiles(\"${tmpDir.absolutePathString()}${File.separator}**${File.separator}Test2.kt\").toList())\n            .containsExactlyInAnyOrder(\n                tmpDir.resolve(\"folder1\").resolve(\"subFolder11\").resolve(\"Test2.kt\"),\n                tmpDir.resolve(\"folder2\").resolve(\"Test2.kt\"),\n            )\n    }\n\n    @Test\n    fun listByFilesWithRelativePath() {\n        Assertions.assertThat(tmpDir.listFiles(\"folder1/subFolder11/*.kt\").toList())\n            .containsExactlyInAnyOrder(\n                tmpDir.resolve(\"folder1\").resolve(\"subFolder11\").resolve(\"Test1.kt\"),\n                tmpDir.resolve(\"folder1\").resolve(\"subFolder11\").resolve(\"Test2.kt\"),\n            )\n    }\n\n    @Test\n    @EnabledOnOs(OS.WINDOWS)\n    fun listByFilesWithRelativePathWindows() {\n        Assertions.assertThat(tmpDir.listFiles(\"folder1\\\\subFolder11\\\\*.kt\").toList())\n            .containsExactlyInAnyOrder(\n                tmpDir.resolve(\"folder1\").resolve(\"subFolder11\").resolve(\"Test1.kt\"),\n                tmpDir.resolve(\"folder1\").resolve(\"subFolder11\").resolve(\"Test2.kt\"),\n            )\n    }\n\n    @Test\n    fun listByFilesWithEmptyResult() {\n        Assertions.assertThat(tmpDir.listFiles(\"**/*.kts\").toList())\n            .isEmpty()\n    }\n\n    @Test\n    fun listByFilesWithParentFolder() {\n        Assertions.assertThat(tmpDir.resolve(\"folder1\").listFiles(\"../*/*.kt\").toList())\n            .containsExactlyInAnyOrder(\n                tmpDir.resolve(\"folder2\").resolve(\"Test1.kt\"),\n                tmpDir.resolve(\"folder2\").resolve(\"Test2.kt\"),\n                tmpDir.resolve(\"folder2\").resolve(\"Test3.kt\"),\n            )\n    }\n\n    @Test\n    fun listByFilesWithFolder() {\n        Assertions.assertThat(tmpDir.listFiles(\"folder2\").toList())\n            .containsExactlyInAnyOrder(\n                tmpDir.resolve(\"folder2\").resolve(\"Test1.kt\"),\n                tmpDir.resolve(\"folder2\").resolve(\"Test2.kt\"),\n                tmpDir.resolve(\"folder2\").resolve(\"Test3.kt\"),\n            )\n\n\n        Assertions.assertThat(tmpDir.listFiles(\"folder1\").toList())\n            .containsExactlyInAnyOrder(\n                tmpDir.resolve(\"folder1\").resolve(\"subFolder11\").resolve(\"Test1.kt\"),\n                tmpDir.resolve(\"folder1\").resolve(\"subFolder11\").resolve(\"Test2.kt\"),\n                tmpDir.resolve(\"folder1\").resolve(\"subFolder12\").resolve(\"Test1.kt\"),\n            )\n    }\n\n    @Test\n    fun listByFilesWithNegative() {\n        Assertions.assertThat(tmpDir.listFiles(\"**/*.kt\", \"!**/subFolder11/*.kt\", \"!**/Test3.kt\").toList())\n            .containsExactlyInAnyOrder(\n                tmpDir.resolve(\"folder1\").resolve(\"subFolder12\").resolve(\"Test1.kt\"),\n                tmpDir.resolve(\"folder2\").resolve(\"Test1.kt\"),\n                tmpDir.resolve(\"folder2\").resolve(\"Test2.kt\"),\n            )\n    }\n\n    companion object {\n        @JvmStatic\n        @TempDir\n        internal var tmpDir: Path = Paths.get(\"/invalid\")\n\n        @BeforeAll\n        @JvmStatic\n        internal fun setupHierarchy() {\n            tmpDir.resolveAndCreateDirectory(\"folder1\")\n                .also { folder1 ->\n                    folder1.resolveAndCreateDirectory(\"subFolder11\")\n                        .also { subFolder11 ->\n                            subFolder11.resolveAndCreateFile(\"Test1.kt\")\n                            subFolder11.resolveAndCreateFile(\"Test2.kt\")\n                        }\n                    folder1.resolveAndCreateDirectory(\"subFolder12\")\n                        .also { subFolder12 ->\n                            subFolder12.resolveAndCreateFile(\"Test1.kt\")\n                        }\n                }\n            tmpDir.resolveAndCreateDirectory(\"folder2\")\n                .also { folder2 ->\n                    folder2.resolveAndCreateFile(\"Test1.kt\")\n                    folder2.resolveAndCreateFile(\"Test2.kt\")\n                    folder2.resolveAndCreateFile(\"Test3.kt\")\n                }\n        }\n\n        private fun Path.resolveAndCreateDirectory(name: String): Path = resolve(name).also {\n            it.createDirectory()\n        }\n\n        private fun Path.resolveAndCreateFile(name: String): Path = resolve(name).also {\n            it.createFile().writeText(\"Test file: $name\")\n        }\n    }\n}\n"
  },
  {
    "path": "diktat-cli/src/test/resources/test/smoke/.editorconfig",
    "content": "# https://editorconfig.org\nroot = true\n[{*.kt,*.kts}]\n# disable ktlint rules\nktlint_standard = disabled\nktlint_experimental = disabled\nktlint_test = disabled\nktlint_custom = disabled"
  },
  {
    "path": "diktat-cli/src/test/resources/test/smoke/.gitignore",
    "content": "/diktat.jar\n/diktat-analysis.yml\n/ktlint\n/save-*-mingwX64.exe\n/tmpSave.txt\n/.save-cli/\n"
  },
  {
    "path": "diktat-cli/src/test/resources/test/smoke/build.gradle.kts_",
    "content": "import com.saveourtool.diktat.generation.docs.generateAvailableRules\n\nplugins {\n    kotlin(\"jvm\") version \"1.4.21\"\n    id(\"com.saveourtool.diktat\") version \"2.0.0\"\n}\n\nrepositories {\n    mavenCentral()\n    maven { url = uri(\"https://example.com\") }\n}\n\nval generateAvailableRules by tasks.register(\"generateAvailableRules\") {\n    dependsOn(\"generateRulesMapping\")\n    doFirst {\n        generateAvailableRules(rootDir, file(\"$rootDir/../wp\"))\n    }\n}\n\nval updateDocumentation = tasks.register(\"updateDocumentation\") {\n    dependsOn(\n        \"generateRulesMapping\",\n        \"generateAvailableRules\",\n        \"generateFullDoc\",\n        \"generateCodeStyle\"\n    )\n}\n\ndiktat {\n    debug = true\n    inputs { include(\"buildSrc/**/*.kt\", \"*.kts\") }\n}\n"
  },
  {
    "path": "diktat-cli/src/test/resources/test/smoke/save.toml",
    "content": "[general]\nexecCmd=\"java -showversion -jar diktat.jar --log-level debug\"\ntags = [\"smokeTest\"]\ndescription = \"SmokeTest\"\nsuiteName = \"SmokeTest\"\nlanguage = \"Kotlin\"\nexpectedWarningsPattern = \"// ;warn:?(.*):(\\\\d*): (.+)\"\ntimeOutMillis = 3600000\n\n[\"fix and warn\"]\n    [\"fix and warn\".fix]\n        execFlags=\"--mode fix\"\n    [\"fix and warn\".warn]\n        lineCaptureGroup = 1\n        columnCaptureGroup = 2\n        messageCaptureGroup = 3\n        lineCaptureGroupOut = 2\n        columnCaptureGroupOut = 3\n        messageCaptureGroupOut = 4\n        actualWarningsPattern = \"(\\\\w+\\\\..+):(\\\\d+):(\\\\d+): (\\\\[.*\\\\].*)$\"\n        exactWarningsMatch = false\n        warningTextHasColumn = true\n        warningTextHasLine = true\n"
  },
  {
    "path": "diktat-cli/src/test/resources/test/smoke/src/jsMain/kotlin/com/saveourtool/diktat/scripts/ScriptExpected.kt",
    "content": "package com.saveourtool.diktat.scripts\n\nimport kotlinx.browser.document\n\nfun main() {\n    (document.getElementById(\"myId\") as HTMLElement).click()\n}\n"
  },
  {
    "path": "diktat-cli/src/test/resources/test/smoke/src/jsMain/kotlin/com/saveourtool/diktat/scripts/ScriptTest.kt",
    "content": "package com.saveourtool.diktat.js\n\nimport kotlinx.browser.document\n\nfun main() {\n    (document.getElementById(\"myId\") as HTMLElement).click()\n}"
  },
  {
    "path": "diktat-cli/src/test/resources/test/smoke/src/main/kotlin/Bug1Expected.kt",
    "content": "// ;warn:$line:1: [FILE_NAME_MATCH_CLASS] file name is incorrect - it should match with the class described in it if there is the only one class declared: Bug1Expected.kt vs D{{.*}}\npackage com.saveourtool.diktat\n\n// ;warn:$line:1: [MISSING_KDOC_TOP_LEVEL] all public and internal top-level classes and functions should have Kdoc: D (cannot be auto-corrected){{.*}}\n// ;warn:7: [CLASS_NAME_INCORRECT] class/enum/interface name should be in PascalCase and should contain only latin (ASCII) letters or numbers: D{{.*}}\n// ;warn:7: [IDENTIFIER_LENGTH] identifier's length is incorrect, it should be in range of [2, 64] symbols: D (cannot be auto-corrected){{.*}}\nclass D {\n    // ;warn:$line:5: [MISSING_KDOC_CLASS_ELEMENTS] all public, internal and protected classes, functions and variables inside the class should have Kdoc: x (cannot be auto-corrected){{.*}}\n    val x = 0\n\n    /**\n     // ;warn:8: [KDOC_NO_EMPTY_TAGS] no empty descriptions in tag blocks are allowed: @return (cannot be auto-corrected){{.*}}\n     * @return\n     */\n    fun bar(): Bar {\n        // ;warn:19: [MAGIC_NUMBER] avoid using magic numbers, instead define constants with clear names describing what the magic number means: 42 (cannot be auto-corrected){{.*}}\n        val qux = 42\n        return Bar(qux)\n    }\n}\n\n/**\n * @param foo\n */\nfun readFile(foo: Foo) {\n    var bar: Bar\n}\n"
  },
  {
    "path": "diktat-cli/src/test/resources/test/smoke/src/main/kotlin/Bug1Test.kt",
    "content": "package test.smoke.src.main.kotlin\n\nfun readFile(foo: Foo) {\n    var bar: Bar\n}\n\nclass D {val x = 0\nfun bar(): Bar {val qux = 42; return Bar(qux)}\n}\n"
  },
  {
    "path": "diktat-cli/src/test/resources/test/smoke/src/main/kotlin/DefaultPackageExpected.kt",
    "content": "// ;warn:1:1: [FILE_NAME_MATCH_CLASS] file name is incorrect - it should match with the class described in it if there is the only one class declared: DefaultPackageExpected.kt vs Example{{.*}}\n// ;warn:3:1: [FILE_INCORRECT_BLOCKS_ORDER] general structure of kotlin source file is wrong, parts are in incorrect order: @file:Suppress{{.*}}\n@file:Suppress(\n    \"PACKAGE_NAME_MISSING\",\n    \"PACKAGE_NAME_INCORRECT_PATH\",\n    \"PACKAGE_NAME_INCORRECT_PREFIX\"\n)\n\n/**\n * Dolor sit amet\n */\nclass Example\n"
  },
  {
    "path": "diktat-cli/src/test/resources/test/smoke/src/main/kotlin/DefaultPackageTest.kt",
    "content": "@file:Suppress(\n    \"PACKAGE_NAME_MISSING\",\n    \"PACKAGE_NAME_INCORRECT_PATH\",\n    \"PACKAGE_NAME_INCORRECT_PREFIX\"\n)\n/**\n * Dolor sit amet\n */\nclass Example"
  },
  {
    "path": "diktat-cli/src/test/resources/test/smoke/src/main/kotlin/Example1-2Expected.kt",
    "content": "package test.smoke\n\nclass example{ @get : JvmName ( \"getIsValid\" )\n    val isValid = true\n\n    fun Foo.foo() { }\n\n    val foo:Int =1\n\n/**\n * @param x\n * @param y\n * @return\n */\nfun bar(x :Int,y:Int) :Int {\nreturn   x+ y}\n\n    /**\n * @param sub\n * @return\n */\nfun String.countSubStringOccurrences(sub: String): Int {\n        // println(\"sub: $sub\")\n        return this.split(sub).size - 1\n    }\n\n    /**\n * @return\n */\nfun String.splitPathToDirs(): List<String> =\n            this.replace(\"\\\\\", \"/\")        .replace(\"//\", \"/\")\n                    .split(\"/\")\n\n/**\n * @param x\n * @param y\n * @return\n */\nfun foo(x :  Int\n            ,\n             y: Int ): Int {\n        return x +\n    (y +\n     bar(x,y)\n  )\n    }\n}\n\n"
  },
  {
    "path": "diktat-cli/src/test/resources/test/smoke/src/main/kotlin/Example1Expected.kt",
    "content": "// ;warn:$line:1: [FILE_NAME_MATCH_CLASS] file name is incorrect - it should match with the class described in it if there is the only one class declared: Example1Expected.kt vs Example{{.*}}\npackage com.saveourtool.diktat\n\n// ;warn:$line:1: [MISSING_KDOC_TOP_LEVEL] all public and internal top-level classes and functions should have Kdoc: Example (cannot be auto-corrected){{.*}}\nclass Example {\n    // ;warn:$line:5: [MISSING_KDOC_CLASS_ELEMENTS] all public, internal and protected classes, functions and variables inside the class should have Kdoc: isValid (cannot be auto-corrected){{.*}}\n    @get:JvmName(\"getIsValid\")\n    val isValid = true\n    // ;warn:$line:5: [MISSING_KDOC_CLASS_ELEMENTS] all public, internal and protected classes, functions and variables inside the class should have Kdoc: foo (cannot be auto-corrected){{.*}}\n    val foo: Int = 1\n\n    // ;warn:$line:5: [MISSING_KDOC_CLASS_ELEMENTS] all public, internal and protected classes, functions and variables inside the class should have Kdoc: foo (cannot be auto-corrected){{.*}}\n    // ;warn:$line-1:5: [MISSING_KDOC_ON_FUNCTION] all public, internal and protected functions should have Kdoc with proper tags: foo (cannot be auto-corrected){{.*}}\n    // ;warn:19: [EMPTY_BLOCK_STRUCTURE_ERROR] incorrect format of empty block: empty blocks are forbidden unless it is function with override keyword (cannot be auto-corrected){{.*}}\n    fun Foo.foo() { }\n\n    /**\n     * @param x\n     * @param y\n    // ;warn:8: [KDOC_NO_EMPTY_TAGS] no empty descriptions in tag blocks are allowed: @return (cannot be auto-corrected){{.*}}\n     * @return\n     */\n    fun bar(x: Int, y: Int): Int = x + y\n\n    /**\n     * @param sub\n    // ;warn:8: [KDOC_NO_EMPTY_TAGS] no empty descriptions in tag blocks are allowed: @return (cannot be auto-corrected){{.*}}\n     * @return\n     */\n    fun String.countSubStringOccurrences(sub: String): Int {\n        // println(\"sub: $sub\")\n        return this.split(sub).size - 1\n    }\n\n    /**\n    // ;warn:8: [KDOC_NO_EMPTY_TAGS] no empty descriptions in tag blocks are allowed: @return (cannot be auto-corrected){{.*}}\n     * @return\n     */\n    fun String.splitPathToDirs(): List<String> =\n            this.replace(\"\\\\\", \"/\").replace(\"//\", \"/\")\n                .split(\"/\")\n\n    /**\n     * @param x\n     * @param y\n    // ;warn:8: [KDOC_NO_EMPTY_TAGS] no empty descriptions in tag blocks are allowed: @return (cannot be auto-corrected){{.*}}\n     * @return\n     */\n    fun foo(x: Int,\n            y: Int): Int = x +\n            (y +\n                    bar(x, y)\n            )\n}\n"
  },
  {
    "path": "diktat-cli/src/test/resources/test/smoke/src/main/kotlin/Example1Test.kt",
    "content": "package test.smoke\n\nclass example{ @get : JvmName ( \"getIsValid\" )\n    val isValid = true\n\n    fun Foo.foo() { }\n\n    val foo:Int =1\nfun bar(x :Int,y:Int) :Int {\nreturn   x+ y}\n\n    fun String.countSubStringOccurrences(sub: String): Int {\n        // println(\"sub: $sub\")\n        return this.split(sub).size - 1\n    }\n\n    fun String.splitPathToDirs(): List<String> =\n            this.replace(\"\\\\\", \"/\")        .replace(\"//\", \"/\")\n                    .split(\"/\")\n\n\n    fun foo(x :  Int\n            ,\n             y: Int ): Int {\n        return x +\n    (y +\n     bar(x,y)\n  )\n    }\n}\n\n"
  },
  {
    "path": "diktat-cli/src/test/resources/test/smoke/src/main/kotlin/Example2Expected.kt",
    "content": "// ;warn:$line:1: [HEADER_MISSING_IN_NON_SINGLE_CLASS_FILE] files that contain multiple or no classes should contain description of what is inside of this file: there are 2 declared classes and/or objects (cannot be auto-corrected){{.*}}\npackage com.saveourtool.diktat\n\nimport org.slf4j.LoggerFactory\n\nimport java.io.IOException\nimport java.util.Properties\n\n/**\n * @property foo\n * @property bar\n */\n@ExperimentalStdlibApi public data class Example(val foo: Int, val bar: Double) : SuperExample(\"lorem ipsum\")\n\n// ;warn:36:3: [EMPTY_BLOCK_STRUCTURE_ERROR] incorrect format of empty block: empty blocks are forbidden unless it is function with override keyword (cannot be auto-corrected){{.*}}\nprivate class TestException : Exception()\n/* this class is unused */\n// private class Test : RuntimeException()\n\n/**\n * Creates a docker container with [file], prepared to execute it\n *\n * @param runConfiguration a [RunConfiguration] for the supplied binary\n * @param file a file that will be included as an executable\n * @param resources additional resources\n * @param containerName\n * @return id of created container or null if it wasn't created\n * @throws DockerException if docker daemon has returned an error\n * @throws DockerException if docker daemon has returned an error\n * @throws RuntimeException if an exception not specific to docker has occurred\n */\ninternal fun createWithFile(runConfiguration: RunConfiguration,\n                            containerName: String,\n                            file: File,\n                            resources: Collection<File> = emptySet()\n) {}\n\nprivate fun foo(node: ASTNode) {\n    when (node.elementType) {\n        CLASS, FUN, PRIMARY_CONSTRUCTOR, SECONDARY_CONSTRUCTOR -> checkAnnotation(node)\n    }\n    val qwe = a && b\n    val qwe = a &&\n            b\n\n    // comment\n    if (x) {\n        foo()\n    }\n\n    setOf<Object>(IOException(), Properties(), LoggerFactory())\n}\n"
  },
  {
    "path": "diktat-cli/src/test/resources/test/smoke/src/main/kotlin/Example2Test.kt",
    "content": "package test.smoke\n\nimport java.io.IOException\nimport java.util.Properties\nimport kotlin.system.exitProcess\nimport org.slf4j.LoggerFactory\n\ndata @ExperimentalStdlibApi public class Example(val foo:Int, val bar:Double):SuperExample(\"lorem ipsum\")\n\nprivate class Test : Exception()\n/*    this class is unused */\n//private class Test : RuntimeException()\n\n/**\n * Creates a docker container with [file], prepared to execute it\n *\n * @param runConfiguration a [RunConfiguration] for the supplied binary\n * @param file a file that will be included as an executable\n * @param resources additional resources\n * @throws DockerException if docker daemon has returned an error\n * @throws DockerException if docker daemon has returned an error\n * @throws RuntimeException if an exception not specific to docker has occurred\n * @return id of created container or null if it wasn't created\n */\ninternal fun createWithFile(runConfiguration: RunConfiguration,\n                            containerName: String,\n                            file: File,\n                            resources: Collection<File> = emptySet()) {}\n\nprivate fun foo (node: ASTNode) {\n    when (node.elementType) {\n        CLASS, FUN, PRIMARY_CONSTRUCTOR, SECONDARY_CONSTRUCTOR -> checkAnnotation(node)\n    }\n    val qwe = a\n            && b\n    val qwe = a &&\n            b\n\n    if (x) // comment\n        foo()\n\n    setOf<Object>(IOException(), Properties(), LoggerFactory())\n}\n"
  },
  {
    "path": "diktat-cli/src/test/resources/test/smoke/src/main/kotlin/Example3Expected.kt",
    "content": "// ;warn:$line:1: [HEADER_MISSING_IN_NON_SINGLE_CLASS_FILE] files that contain multiple or no classes should contain description of what is inside of this file: there are 6 declared classes and/or objects (cannot be auto-corrected){{.*}}\npackage com.saveourtool.diktat\n\n/*\n * Copyright (c) Your Company Name Here. 2010-2020\n */\n\n/**\n * @property name\n */\nclass HttpClient(var name: String) {\n    // ;warn:$line:5: [MISSING_KDOC_CLASS_ELEMENTS] all public, internal and protected classes, functions and variables inside the class should have Kdoc: url (cannot be auto-corrected){{.*}}\n    var url: String = \"\"\n    // ;warn:$line:5: [MISSING_KDOC_CLASS_ELEMENTS] all public, internal and protected classes, functions and variables inside the class should have Kdoc: port (cannot be auto-corrected){{.*}}\n    var port: String = \"\"\n    // ;warn:$line:5: [MISSING_KDOC_CLASS_ELEMENTS] all public, internal and protected classes, functions and variables inside the class should have Kdoc: timeout (cannot be auto-corrected){{.*}}\n    var timeout = 0\n\n    // ;warn:$line:5: [MISSING_KDOC_CLASS_ELEMENTS] all public, internal and protected classes, functions and variables inside the class should have Kdoc: doRequest (cannot be auto-corrected){{.*}}\n    // ;warn:$line-1:5: [MISSING_KDOC_ON_FUNCTION] all public, internal and protected functions should have Kdoc with proper tags: doRequest (cannot be auto-corrected){{.*}}\n    // ;warn:21: [EMPTY_BLOCK_STRUCTURE_ERROR] incorrect format of empty block: empty blocks are forbidden unless it is function with override keyword (cannot be auto-corrected){{.*}}\n    fun doRequest() {}\n}\n\n// ;warn:$line:1: [MISSING_KDOC_TOP_LEVEL] all public and internal top-level classes and functions should have Kdoc: Example (cannot be auto-corrected){{.*}}\nclass Example {\n    // ;warn:$line:5: [MISSING_KDOC_CLASS_ELEMENTS] all public, internal and protected classes, functions and variables inside the class should have Kdoc: foo (cannot be auto-corrected){{.*}}\n    // ;warn:$line-1:5: [MISSING_KDOC_ON_FUNCTION] all public, internal and protected functions should have Kdoc with proper tags: foo (cannot be auto-corrected){{.*}}\n    fun foo() {\n        if (condition1 && condition2) {\n            bar()\n        }\n\n        if (condition3) {\n            if (condition4) {\n                foo()\n            } else {\n                bar()\n            }\n        } else {\n            foo()\n        }\n    }\n}\n\n// ;warn:$line:1: [MISSING_KDOC_TOP_LEVEL] all public and internal top-level classes and functions should have Kdoc: IssueType (cannot be auto-corrected){{.*}}\nenum class IssueType {\n    PROJECT_STRUCTURE, TESTS, VCS\n}\n\n// ;warn:$line:1: [MISSING_KDOC_TOP_LEVEL] all public and internal top-level classes and functions should have Kdoc: IssueType2 (cannot be auto-corrected){{.*}}\nenum class IssueType2 {\n    PROJECT_STRUCTURE,\n    TESTS,\n    VCS,\n    ;\n\n    /**\n     * @param bar\n     // ;warn:8: [KDOC_NO_EMPTY_TAGS] no empty descriptions in tag blocks are allowed: @return (cannot be auto-corrected){{.*}}\n     * @return\n     */\n    fun foo(bar: Int) = bar\n\n    companion object\n}\n\n// ;warn:$line:1: [MISSING_KDOC_TOP_LEVEL] all public and internal top-level classes and functions should have Kdoc: IssueType3 (cannot be auto-corrected){{.*}}\nenum class IssueType3 {\n    // ;warn:5: [IDENTIFIER_LENGTH] identifier's length is incorrect, it should be in range of [2, 64] symbols: A (cannot be auto-corrected){{.*}}\n    A,\n    // ;warn:5: [CONFUSING_IDENTIFIER_NAMING] it's a bad name for identifier: better name is: bt, nxt (cannot be auto-corrected){{.*}}\n    // ;warn:5: [IDENTIFIER_LENGTH] identifier's length is incorrect, it should be in range of [2, 64] symbols: B (cannot be auto-corrected){{.*}}\n    B,\n    // ;warn:5: [IDENTIFIER_LENGTH] identifier's length is incorrect, it should be in range of [2, 64] symbols: C (cannot be auto-corrected){{.*}}\n    C,\n    // ;warn:5: [CONFUSING_IDENTIFIER_NAMING] it's a bad name for identifier: better name is: obj, dgt (cannot be auto-corrected){{.*}}\n    // ;warn:5: [IDENTIFIER_LENGTH] identifier's length is incorrect, it should be in range of [2, 64] symbols: D (cannot be auto-corrected){{.*}}\n    D,\n    ;\n}\n\n// ;warn:$line:1: [MISSING_KDOC_TOP_LEVEL] all public and internal top-level classes and functions should have Kdoc: Foo (cannot be auto-corrected){{.*}}\n// ;warn:$line+4:8: [KDOC_NO_NEWLINE_AFTER_SPECIAL_TAGS] in KDoc there should be exactly one empty line after special tags: @implNote{{.*}}\n// ;warn:$line+5:23: [EMPTY_BLOCK_STRUCTURE_ERROR] incorrect format of empty block: empty blocks are forbidden unless it is function with override keyword (cannot be auto-corrected){{.*}}\nclass Foo {\n    /**\n     * @implNote lorem ipsum\n     */\n    private fun foo() {}\n}\n\n// ;warn:$line:1: [MISSING_KDOC_TOP_LEVEL] all public and internal top-level classes and functions should have Kdoc: mains (cannot be auto-corrected){{.*}}\n// ;warn:$line-1:1: [MISSING_KDOC_ON_FUNCTION] all public, internal and protected functions should have Kdoc with proper tags: mains (cannot be auto-corrected){{.*}}\nfun mains() {\n    val httpClient = HttpClient(\"myConnection\")\n        .apply {\n            url = \"http://example.com\"\n            port = \"8080\"\n            // ;warn:23: [MAGIC_NUMBER] avoid using magic numbers, instead define constants with clear names describing what the magic number means: 100 (cannot be auto-corrected){{.*}}\n            timeout = 100\n        }\n    httpClient.doRequest()\n}\n"
  },
  {
    "path": "diktat-cli/src/test/resources/test/smoke/src/main/kotlin/Example3Test.kt",
    "content": "/*\n * Copyright (c) Your Company Name Here. 2010-2020\n */\n\nclass HttpClient {\n    var name: String\n    var url: String = \"\"\n    var port: String = \"\"\n    var timeout = 0\n\n    constructor(name: String) {\n        this.name = name\n    }\n\n    fun doRequest() {}\n}\n\nfun mains() {\n    val httpClient = HttpClient(\"myConnection\")\n            .apply {\n                url = \"http://example.com\"\n                port = \"8080\"\n                timeout = 100\n            }\n    httpClient.doRequest()\n}\n\nclass Example {\n    fun foo() {\n        if (condition1)\n            if (condition2)\n                bar()\n\n        if (condition3)\n            if (condition4)\n                foo()\n            else\n                bar()\n        else\n            foo()\n    }\n}\n\nenum class IssueType {\n    VCS, PROJECT_STRUCTURE, TESTS\n}\n\nenum class IssueType2 {\n    VCS, PROJECT_STRUCTURE, TESTS;\n\n    companion object\n    fun foo(bar: Int) = bar\n}\n\nenum class IssueType3 {\n    A,\n    C,\n    B,\n    D,\n    ;\n}\n\nclass Foo {\n    /**\n     * @implNote lorem ipsum\n     */\n    private fun foo() {}\n}\n\n"
  },
  {
    "path": "diktat-cli/src/test/resources/test/smoke/src/main/kotlin/Example4Expected.kt",
    "content": "// ;warn:$line:1: [FILE_NAME_MATCH_CLASS] file name is incorrect - it should match with the class described in it if there is the only one class declared: Example4Expected.kt vs SpecialTagsInKdoc{{.*}}\npackage com.saveourtool.diktat\n\n// ;warn:$line:1: [MISSING_KDOC_TOP_LEVEL] all public and internal top-level classes and functions should have Kdoc: SpecialTagsInKdoc (cannot be auto-corrected){{.*}}\nclass SpecialTagsInKdoc {\n    /**\n     * Empty function to test KDocs\n     * @apiNote foo\n     *\n     * @implSpec bar\n     *\n     * @implNote baz\n     *\n     // ;warn:8: [KDOC_NO_EMPTY_TAGS] no empty descriptions in tag blocks are allowed: @return (cannot be auto-corrected){{.*}}\n     * @return\n     */\n    fun test() = Unit\n}\n\n// ;warn:$line:1: [MISSING_KDOC_TOP_LEVEL] all public and internal top-level classes and functions should have Kdoc: `method name incorrect, part 4` (cannot be auto-corrected){{.*}}\n// ;warn:$line-1:1: [MISSING_KDOC_ON_FUNCTION] all public, internal and protected functions should have Kdoc with proper tags: `method name incorrect, part 4` (cannot be auto-corrected){{.*}}\n// ;warn:5: [BACKTICKS_PROHIBITED] backticks should not be used in identifier's naming. The only exception test methods marked with @Test annotation: `method name incorrect, part 4` (cannot be auto-corrected){{.*}}\nfun `method name incorrect, part 4`() {\n    val code = \"\"\"\n                  class TestPackageName {\n                    fun methODTREE(): String {\n                    }\n                  }\n                \"\"\".trimIndent()\n    lintMethod(code, LintError(2, 7, ruleId, \"${FUNCTION_NAME_INCORRECT_CASE.warnText()} methODTREE\", true))\n\n    foo\n        // we are calling bar\n        .bar()\n\n    bar\n        /* This is a block comment */\n        .foo()\n}\n\n// ;warn:$line:1: [MISSING_KDOC_TOP_LEVEL] all public and internal top-level classes and functions should have Kdoc: foo (cannot be auto-corrected){{.*}}\n// ;warn:$line-1:1: [MISSING_KDOC_ON_FUNCTION] all public, internal and protected functions should have Kdoc with proper tags: foo (cannot be auto-corrected){{.*}}\nfun foo() {\n    foo(\n        0,\n        { obj -> obj.bar() }\n    )\n\n    bar(\n        0, { obj -> obj.bar() }\n    )\n}\n\n// ;warn:$line:1: [MISSING_KDOC_TOP_LEVEL] all public and internal top-level classes and functions should have Kdoc: bar (cannot be auto-corrected){{.*}}\n// ;warn:$line-1:1: [MISSING_KDOC_ON_FUNCTION] all public, internal and protected functions should have Kdoc with proper tags: bar (cannot be auto-corrected){{.*}}\nfun bar() {\n    val diktatExtension = project.extensions.create(DIKTAT_EXTENSION, DiktatExtension::class.java).apply {\n        inputs = project.fileTree(\"src\").apply {\n            include(\"**/*.kt\")\n        }\n        reporter = PlainReporter(System.out)\n    }\n}\n\n// ;warn:$line:1: [MISSING_KDOC_TOP_LEVEL] all public and internal top-level classes and functions should have Kdoc: boo (cannot be auto-corrected){{.*}}\n// ;warn:$line-1:1: [MISSING_KDOC_ON_FUNCTION] all public, internal and protected functions should have Kdoc with proper tags: boo (cannot be auto-corrected){{.*}}\n@Suppress(\"\")\nfun boo() {\n    val y = \"akgjsaujtmaksdkfasakgjsaujtmaksdkfasakgjsaujtmaksdkfasakgjsaujtm\" +\n            \" aksdkfasfasakgjsaujtmaksdfasafasakgjsaujtmaksdfasakgjsaujtmaksdfasakgjsaujtmaksdfasakgjsaujtmaksdfasakgjsaujtmaksdkgjsaujtmaksdfasakgjsaujtmaksd\"\n}\n"
  },
  {
    "path": "diktat-cli/src/test/resources/test/smoke/src/main/kotlin/Example4Test.kt",
    "content": "package com.saveourtool.diktat\n\nclass SpecialTagsInKdoc {\n\n    /**\n     * Empty function to test KDocs\n     * @apiNote foo\n     * @implSpec bar\n     *\n     *\n     * @implNote baz\n     */\n    fun test() = Unit\n}\n\nfun `method name incorrect, part 4`() {\n    val code = \"\"\"\n                  class TestPackageName {\n                    fun methODTREE(): String {\n                    }\n                  }\n                \"\"\".trimIndent()\n    lintMethod(code, LintError(2, 7, ruleId, \"${FUNCTION_NAME_INCORRECT_CASE.warnText()} methODTREE\", true))\n\n    foo\n            // we are calling bar\n            .bar()\n\n    bar\n            /* This is a block comment */\n            .foo()\n}\n\nfun foo() {\n    foo(\n            0,\n            { obj -> obj.bar() }\n    )\n\n    bar(\n            0, { obj -> obj.bar() }\n    )\n}\n\nfun bar() {\n    val diktatExtension = project.extensions.create(DIKTAT_EXTENSION, DiktatExtension::class.java)\n    diktatExtension.inputs = project.fileTree(\"src\").apply {\n        include(\"**/*.kt\")\n    }\n    diktatExtension.reporter = PlainReporter(System.out)\n}\n\n@Suppress(\"\")\nfun boo() {\n    val y = \"akgjsaujtmaksdkfasakgjsaujtmaksdkfasakgjsaujtmaksdkfasakgjsaujtm aksdkfasfasakgjsaujtmaksdfasafasakgjsaujtmaksdfasakgjsaujtmaksdfasakgjsaujtmaksdfasakgjsaujtmaksdfasakgjsaujtmaksdkgjsaujtmaksdfasakgjsaujtmaksd\"\n}\n"
  },
  {
    "path": "diktat-cli/src/test/resources/test/smoke/src/main/kotlin/Example5Expected.kt",
    "content": "// ;warn:$line:1: [FILE_NAME_MATCH_CLASS] file name is incorrect - it should match with the class described in it if there is the only one class declared: Example5Expected.kt vs Some{{.*}}\n/*\n    Copyright 2018-2024 John Doe.\n    Licensed under the Apache License, Version 2.0 (the \"License\");\n    you may not use this file except in compliance with the License.\n    You may obtain a copy of the License at\n\n        http://www.apache.org/licenses/LICENSE-2.0\n*/\n\npackage com.saveourtool.diktat\n\n// ;warn:$line:1: [MISSING_KDOC_TOP_LEVEL] all public and internal top-level classes and functions should have Kdoc: Some (cannot be auto-corrected){{.*}}\n// ;warn:$line-1:1: [USE_DATA_CLASS] this class can be converted to a data class: Some (cannot be auto-corrected){{.*}}\nclass Some {\n    // ;warn:$line:5: [MISSING_KDOC_CLASS_ELEMENTS] all public, internal and protected classes, functions and variables inside the class should have Kdoc: config (cannot be auto-corrected){{.*}}\n    val config = Config()\n}\n"
  },
  {
    "path": "diktat-cli/src/test/resources/test/smoke/src/main/kotlin/Example5Test.kt",
    "content": "package com.saveourtool.diktat\n\nclass Some {\n    val config = Config()\n}\n"
  },
  {
    "path": "diktat-cli/src/test/resources/test/smoke/src/main/kotlin/Example6Expected.kt",
    "content": "// ;warn:$line:1: [HEADER_MISSING_IN_NON_SINGLE_CLASS_FILE] files that contain multiple or no classes should contain description of what is inside of this file: there are 0 declared classes and/or objects (cannot be auto-corrected){{.*}}\npackage com.saveourtool.diktat\n\nval foo =\n        \"\"\"\n            some\n            cool\n            text\n        \"\"\".trimIndent()\n\nval bar =\n        \"\"\"\n            | some\n            | text\n        \"\"\".trimMargin()\n\nval text =\n        \"\"\"\n       x\n    \"\"\"\n\nval dockerFileAsText =\n        \"\"\"\n            FROM $baseImage someTest\n            COPY resources $resourcesPath\n            RUN /bin/bash\n        \"\"\".trimIndent()  // RUN command shouldn't matter because it will be replaced on container creation\n"
  },
  {
    "path": "diktat-cli/src/test/resources/test/smoke/src/main/kotlin/Example6Test.kt",
    "content": "package com.saveourtool.diktat\n\nval foo =\n    \"\"\"\n        some\n        cool\n        text\n    \"\"\".trimIndent()\n\nval bar =\n    \"\"\"\n        | some\n        | text\n    \"\"\".trimMargin()\n\nval text =\n    \"\"\"\n       x\n    \"\"\"\n\nval dockerFileAsText =\n                \"\"\"\n                    FROM $baseImage someTest\n                    COPY resources $resourcesPath\n                    RUN /bin/bash\n                \"\"\".trimIndent()  // RUN command shouldn't matter because it will be replaced on container creation\n"
  },
  {
    "path": "diktat-cli/src/test/resources/test/smoke/src/main/kotlin/Example7Expected.kt",
    "content": "// ;warn:$line:1: [HEADER_MISSING_IN_NON_SINGLE_CLASS_FILE] files that contain multiple or no classes should contain description of what is inside of this file: there are 0 declared classes and/or objects (cannot be auto-corrected){{.*}}\npackage com.saveourtool.diktat\n\n// ;warn:$line:1: [MISSING_KDOC_TOP_LEVEL] all public and internal top-level classes and functions should have Kdoc: foo (cannot be auto-corrected){{.*}}\n// ;warn:$line-1:1: [MISSING_KDOC_ON_FUNCTION] all public, internal and protected functions should have Kdoc with proper tags: foo (cannot be auto-corrected){{.*}}\nfun foo() {\n    val prop: Int = 0\n\n    prop ?: run {\n        println(\"prop is null\")\n        bar()\n    }\n\n    prop?.let {\n        baz()\n        gaz()\n    }\n\n    prop?.let {\n        doAnotherSmth()\n    } ?: doSmth()\n}\n\n// ;warn:$line:1: [MISSING_KDOC_TOP_LEVEL] all public and internal top-level classes and functions should have Kdoc: fooo (cannot be auto-corrected){{.*}}\n// ;warn:$line-1:1: [MISSING_KDOC_ON_FUNCTION] all public, internal and protected functions should have Kdoc with proper tags: fooo (cannot be auto-corrected){{.*}}\nfun fooo() {\n    if (a) {\n        bar()\n    } else b?.let {\n        baz()\n    }\n        ?: run {\n            qux()\n        }\n}\n"
  },
  {
    "path": "diktat-cli/src/test/resources/test/smoke/src/main/kotlin/Example7Test.kt",
    "content": "package com.saveourtool.diktat\n\nfun foo() {\n    val prop: Int? = null\n\n    if (prop == null) {\n        println(\"prop is null\")\n        bar()\n    }\n\n    if (prop != null) {\n        baz()\n        gaz()\n    }\n\n    if (prop == null) {\n        doSmth()\n    } else {\n        doAnotherSmth()\n    }\n}\n\nfun fooo() {\n    if (a) {\n        bar()\n    } else b?.let {\n        baz()\n    }\n        ?: run {\n            qux()\n        }\n}\n\n"
  },
  {
    "path": "diktat-cli/src/test/resources/test/smoke/src/main/kotlin/Example8Expected.kt",
    "content": "// ;warn:$line:1: [HEADER_MISSING_IN_NON_SINGLE_CLASS_FILE] files that contain multiple or no classes should contain description of what is inside of this file: there are 0 declared classes and/or objects (cannot be auto-corrected) (diktat-ruleset:header-comment)\npackage com.saveourtool.diktat\n\n// ;warn:$line:1: [MISSING_KDOC_TOP_LEVEL] all public and internal top-level classes and functions should have Kdoc: foo (cannot be auto-corrected) (diktat-ruleset:kdoc-comments)\n// ;warn:$line-1:1: [MISSING_KDOC_ON_FUNCTION] all public, internal and protected functions should have Kdoc with proper tags: foo (cannot be auto-corrected) (diktat-ruleset:kdoc-methods)\nfun foo() {\n    // ;warn:28: [WRONG_WHITESPACE] incorrect usage of whitespaces for code separation: , should have 0 space(s) before and 1 space(s) after, but has 0 space(s) after (diktat-ruleset:horizontal-whitespace)\n    val sum: (Int, Int, Int,) -> Int = fun(\n        x,\n        y,\n        z\n    ): Int = x + y + x\n    // ;warn:5: [DEBUG_PRINT] use a dedicated logging library: found println() (cannot be auto-corrected) (diktat-ruleset:debug-print)\n    println(sum(8, 8, 8))\n}\n\n// ;warn:$line:1: [MISSING_KDOC_TOP_LEVEL] all public and internal top-level classes and functions should have Kdoc: boo (cannot be auto-corrected) (diktat-ruleset:kdoc-comments)\n// ;warn:$line-1:1: [MISSING_KDOC_ON_FUNCTION] all public, internal and protected functions should have Kdoc with proper tags: boo (cannot be auto-corrected) (diktat-ruleset:kdoc-methods)\nfun boo() {\n    // ;warn:27: [DEBUG_PRINT] use a dedicated logging library: found println() (cannot be auto-corrected) (diktat-ruleset:debug-print)\n    val message = fun() = println(\"Hello\")\n}\n"
  },
  {
    "path": "diktat-cli/src/test/resources/test/smoke/src/main/kotlin/Example8Test.kt",
    "content": "package com.saveourtool.diktat\n\nfun foo() {\n    val sum: (Int, Int, Int,) -> Int = fun(\n        x,\n        y,\n        z\n    ): Int {\n        return x + y + x\n    }\n    println(sum(8, 8, 8))\n}\n\nfun boo() {\n    val message = fun()=println(\"Hello\")\n}"
  },
  {
    "path": "diktat-cli/src/test/resources/test/smoke/src/main/kotlin/KdocFormattingMultilineTagsExpected.kt",
    "content": "// ;warn:$line:1: [HEADER_MISSING_IN_NON_SINGLE_CLASS_FILE] files that contain multiple or no classes should contain description of what is inside of this file: there are 0 declared classes and/or objects (cannot be auto-corrected) (diktat-ruleset:header-comment)\npackage com.saveourtool.diktat\n\n/**\n * @param bar lorem ipsum\n *\n * dolor sit amet\n// ;warn:4: [KDOC_NO_EMPTY_TAGS] no empty descriptions in tag blocks are allowed: @return (cannot be auto-corrected) (diktat-ruleset:kdoc-formatting)\n * @return\n */\nfun foo1(bar: Bar): Baz {\n    // placeholder\n}\n\n/**\n * @param bar lorem ipsum\n *\n * dolor sit amet\n// ;warn:4: [KDOC_NO_EMPTY_TAGS] no empty descriptions in tag blocks are allowed: @return (cannot be auto-corrected) (diktat-ruleset:kdoc-formatting)\n * @return\n */\nfun foo2(bar: Bar): Baz {\n    // placeholder\n}\n"
  },
  {
    "path": "diktat-cli/src/test/resources/test/smoke/src/main/kotlin/KdocFormattingMultilineTagsTest.kt",
    "content": "/**\n * @param bar lorem ipsum\n *\n * dolor sit amet\n */\nfun foo1(bar: Bar): Baz {\n    // placeholder\n}\n\n/**\n * @param bar lorem ipsum\n *\n * dolor sit amet\n *\n */\nfun foo2(bar: Bar): Baz {\n    // placeholder\n}\n"
  },
  {
    "path": "diktat-cli/src/test/resources/test/smoke/src/main/kotlin/LocalVariableWithOffsetExpected.kt",
    "content": "// ;warn:$line:1: [HEADER_MISSING_IN_NON_SINGLE_CLASS_FILE] files that contain multiple or no classes should contain description of what is inside of this file: there are 0 declared classes and/or objects (cannot be auto-corrected) (diktat-ruleset:header-comment)\npackage com.saveourtool.diktat\n\n// ;warn:$line:1: [MISSING_KDOC_TOP_LEVEL] all public and internal top-level classes and functions should have Kdoc: boo (cannot be auto-corrected) (diktat-ruleset:kdoc-comments)\noverride fun boo() {\n    val listTestResult: MutableList<TestResult> = mutableListOf()\n    files.chunked(warnPluginConfig.batchSize ?: 1).map { chunk ->\n        handleTestFile(chunk.map { it.single() }, warnPluginConfig, generalConfig)\n    }.forEach { listTestResult.addAll(it) }\n}\n"
  },
  {
    "path": "diktat-cli/src/test/resources/test/smoke/src/main/kotlin/LocalVariableWithOffsetTest.kt",
    "content": "package com.saveourtool.diktat\n\n    override fun boo() {\n     val listTestResult: MutableList<TestResult> = mutableListOf()\n    files.chunked(warnPluginConfig.batchSize ?: 1).map { chunk ->\n        handleTestFile(chunk.map { it.single() }, warnPluginConfig, generalConfig)\n    }.forEach { listTestResult.addAll(it) }\n}"
  },
  {
    "path": "diktat-cli/src/test/resources/test/smoke/src/main/kotlin/ManyLineTransformInLongLineExpected.kt",
    "content": "package com.saveourtool.diktat\n\nfun foo() {\n    (1 or 2 or 3 or 4 or 5 or 6 or 7 or 8 or 9 or 10 or 11 or 12 or 13 or 14 or 15 or 16 or 17 or 18 or 19 or 20 or 21 or 22 or 23 or 24 or 25 or 26 or 27 or 28 or 29 or 30 or 31\n    ?: 32 or 33 or 34 or 35 or 36 or 37 or 38 or 39 ?: 40 or 41 or 42 or 43 or 44 or 45 or 46 or 47 or 48 or 49 or 50 or 51 or 52 or 53 + 54 or 55 or 56 or 57 or 58 or 59\n    ?: 60 or 61 or 62 or 63 or 64 or 65 or 66 - 67 or 68 or 69 or 70 or 1 + 2 or 3 or 4 or 5 or 6 or 7 or 8 or 9 or 10 or 11 or 12 or 13 or 14 or 15 or 16 or 17 or 18 + 19 -\n        20 or 21 or 22 or 23 or 24 or 25 or 26 or 27 or 28 or 29 or 30 or 31 or 32 or 33 or 34 or 35 or 36 or 37 or 38 or 39 or 40 or 41 || 42 or 43 or 44 or 45 or 46 or 47 &&\n        48 or 49 ||\n        50 or 51 or 52 or 53 or 54 or 55 or 56 or 57 or 58 or 59 or 60 or 61 or 62 or 63 or 64 or 65 or 66 or 67 or 68 or 69 or 70 or 1 or 2 or 3 or 4 or 5 or 6 or 7 or 8 or 9 or 10 or 11 or\n            12 or 13 or 14 or 15 or 16 or 17 or 18 or 19 or 20 or 21 or 22 or 23 or 24 or 25 or 26 or 27 or 28 or 29 or 30 or 31 or 32 or 33 or 34 or 35 or 36 or 37 or 38 or 39 or 40 or 41 or\n            42 or 43 or 44 or 45 or 46 or 47 or 48 or 49 or 50 or 51 or 52 or 53 or 54 or 55 or 56 or 57 or 58 or 59 or 60 or 61 or 62 or 63 or 64 or 65 or 66 or 67 or 68 or 69 or 70)\n}\n"
  },
  {
    "path": "diktat-cli/src/test/resources/test/smoke/src/main/kotlin/ManyLineTransformInLongLineTest.kt",
    "content": "package com.saveourtool.diktat\n\nfun foo(){\n    (1\n            or 2\n            or 3\n            or 4\n            or 5\n            or 6\n            or 7\n            or 8\n            or 9\n            or 10\n            or 11\n            or 12\n            or 13\n            or 14\n            or 15\n            or 16\n            or 17\n            or 18\n            or 19\n            or 20\n            or 21\n            or 22\n            or 23\n            or 24\n            or 25\n            or 26\n            or 27\n            or 28\n            or 29\n            or 30\n            or 31\n            ?: 32\n            or 33\n            or 34\n            or 35\n            or 36\n            or 37\n            or 38\n            or 39 ?: 40\n            or 41\n            or 42\n            or 43\n            or 44\n            or 45\n            or 46\n            or 47\n            or 48\n            or 49\n            or 50\n            or 51\n            or 52\n            or 53\n            + 54\n            or 55\n            or 56\n            or 57\n            or 58\n            or 59\n            ?: 60\n            or 61\n            or 62\n            or 63\n            or 64\n            or 65\n            or 66\n            - 67\n            or 68\n            or 69\n            or 70\n            or 1\n            + 2\n            or 3\n            or 4\n            or 5\n            or 6\n            or 7\n            or 8\n            or 9\n            or 10\n            or 11\n            or 12\n            or 13\n            or 14\n            or 15\n            or 16\n            or 17\n            or 18\n            + 19\n            - 20\n            or 21\n            or 22\n            or 23\n            or 24\n            or 25\n            or 26\n            or 27\n            or 28\n            or 29\n            or 30\n            or 31\n            or 32\n            or 33\n            or 34\n            or 35\n            or 36\n            or 37\n            or 38\n            or 39\n            or 40\n            or 41\n            || 42\n            or 43\n            or 44\n            or 45\n            or 46\n            or 47\n            && 48\n            or 49\n            || 50\n            or 51\n            or 52\n            or 53\n            or 54\n            or 55\n            or 56\n            or 57\n            or 58\n            or 59\n            or 60\n            or 61\n            or 62\n            or 63\n            or 64\n            or 65\n            or 66\n            or 67\n            or 68\n            or 69\n            or 70\n            or 1\n            or 2\n            or 3\n            or 4\n            or 5\n            or 6\n            or 7\n            or 8\n            or 9\n            or 10\n            or 11\n            or 12\n            or 13\n            or 14\n            or 15\n            or 16\n            or 17\n            or 18\n            or 19\n            or 20\n            or 21\n            or 22\n            or 23\n            or 24\n            or 25\n            or 26\n            or 27\n            or 28\n            or 29\n            or 30\n            or 31\n            or 32\n            or 33\n            or 34\n            or 35\n            or 36\n            or 37\n            or 38\n            or 39\n            or 40\n            or 41\n            or 42\n            or 43\n            or 44\n            or 45\n            or 46\n            or 47\n            or 48\n            or 49\n            or 50\n            or 51\n            or 52\n            or 53\n            or 54\n            or 55\n            or 56\n            or 57\n            or 58\n            or 59\n            or 60\n            or 61\n            or 62\n            or 63\n            or 64\n            or 65\n            or 66\n            or 67\n            or 68\n            or 69\n            or 70)\n}\n"
  },
  {
    "path": "diktat-cli/src/test/resources/test/smoke/src/main/kotlin/NewlinesAfterInterfacesExpected.kt",
    "content": "package com.saveourtool.diktat\n\nclass A<K : Any, P : Any, G : Any> :\n    B<K>(),\n    C<P>,\n    D<G> {}\n"
  },
  {
    "path": "diktat-cli/src/test/resources/test/smoke/src/main/kotlin/NewlinesAfterInterfacesTest.kt",
    "content": "package com.saveourtool.diktat\n\nclass A<K : Any, P : Any, G : Any> : B<K>(), C<P>, D<G> {}\n"
  },
  {
    "path": "diktat-cli/src/test/resources/test/smoke/src/main/kotlin/SemicolonsExpected.kt",
    "content": "package com.saveourtool.diktat\n\nimport io.micrometer.core.instrument.MeterRegistry\nimport io.micrometer.core.instrument.MultiGauge\nimport io.micrometer.core.instrument.Tags\nimport org.springframework.scheduling.annotation.Scheduled\nimport org.springframework.stereotype.Component\n\n@Component\nclass ActiveBinsMetric(meterRegistry: MeterRegistry, private val binRepository: BinRepository) {\n    private val metric = MultiGauge.builder(ACTIVE_BINS_METRIC_NAME)\n        .register(meterRegistry)\n\n    @Scheduled(fixedDelay = DELAY)\n    fun queryDb() {\n        metric.register(\n            binRepository\n                .countActiveWithPartsNumber()\n                .toRangeMap()\n                .map {\n                    MultiGauge.Row.of(\n                        Tags.of(NUMBER_OF_EGGS_LABEL, it.key),\n                        it.value\n                    )\n                }, true)\n    }\n\n    private fun List<NumberOfBinsAndParts>.toRangeMap(): MutableMap<String, Long> {\n        var total = 0L\n        val map = mutableMapOf<String, Long>()\n        numberOfEggsBuckets.forEach { map[it] = 0 }\n\n        this.forEach {\n            total += it.numberOfBins\n            when (it.numberOfParts) {\n                1 -> map[EGG_1_BUCKET_LABEL] = it.numberOfBins\n                2 -> map[EGG_2_BUCKET_LABEL] = it.numberOfBins\n                3 -> map[EGG_3_BUCKET_LABEL] = it.numberOfBins\n                in 4..5 -> map[EGG_4_5_BUCKET_LABEL] = it.numberOfBins\n                in 7..9 -> map[EGG_7_9_BUCKET_LABEL] = it.numberOfBins\n                in 10..Int.MAX_VALUE -> map[EGG_OVER_10_BUCKET_LABEL] = it.numberOfBins\n            }\n        }\n\n        map[ALL_ACTIVE_BINS_LABEL] = total\n        return map\n    }\n\n    companion object {\n        private const val ACTIVE_BINS_METRIC_NAME = \"c.concurrent.bins\"\n        private const val ALL_ACTIVE_BINS_LABEL = \"total\"\n        private const val EGG_1_BUCKET_LABEL = \"1\"\n        private const val EGG_2_BUCKET_LABEL = \"2\"\n        private const val EGG_3_BUCKET_LABEL = \"3\"\n        private const val EGG_4_5_BUCKET_LABEL = \"4-5\"\n        private const val EGG_7_9_BUCKET_LABEL = \"7-9\"\n        private const val EGG_OVER_10_BUCKET_LABEL = \"10+\"\n        private const val NUMBER_OF_EGGS_LABEL = \"numberOfEggs\"\n        private val numberOfEggsBuckets = setOf(\n            EGG_1_BUCKET_LABEL,\n            EGG_2_BUCKET_LABEL,\n            EGG_3_BUCKET_LABEL,\n            EGG_4_5_BUCKET_LABEL,\n            EGG_7_9_BUCKET_LABEL,\n            EGG_OVER_10_BUCKET_LABEL,\n            ALL_ACTIVE_BINS_LABEL)\n    }\n}\n"
  },
  {
    "path": "diktat-cli/src/test/resources/test/smoke/src/main/kotlin/SemicolonsTest.kt",
    "content": "import io.micrometer.core.instrument.MeterRegistry\nimport io.micrometer.core.instrument.MultiGauge\nimport io.micrometer.core.instrument.Tags;\nimport org.springframework.scheduling.annotation.Scheduled;\nimport org.springframework.stereotype.Component;\n\n@Component\nclass ActiveBinsMetric(meterRegistry: MeterRegistry, private val binRepository: BinRepository) {\n\n    companion object {\n        private const val ACTIVE_BINS_METRIC_NAME = \"c.concurrent.bins\";\n        private const val NUMBER_OF_EGGS_LABEL = \"numberOfEggs\";\n        private const val ALL_ACTIVE_BINS_LABEL = \"total\";\n        private const val EGG_1_BUCKET_LABEL = \"1\";\n        private const val EGG_2_BUCKET_LABEL = \"2\";\n        private const val EGG_3_BUCKET_LABEL = \"3\";\n        private const val EGG_4_5_BUCKET_LABEL = \"4-5\";\n        private const val EGG_7_9_BUCKET_LABEL = \"7-9\";\n        private const val EGG_OVER_10_BUCKET_LABEL = \"10+\";\n        private val numberOfEggsBuckets = setOf(\n                EGG_1_BUCKET_LABEL,\n                EGG_2_BUCKET_LABEL,\n                EGG_3_BUCKET_LABEL,\n                EGG_4_5_BUCKET_LABEL,\n                EGG_7_9_BUCKET_LABEL,\n                EGG_OVER_10_BUCKET_LABEL,\n                ALL_ACTIVE_BINS_LABEL);\n\n    }\n\n    private val metric = MultiGauge.builder(ACTIVE_BINS_METRIC_NAME)\n            .register(meterRegistry);\n\n    @Scheduled(fixedDelay = DELAY)\n    fun queryDB() {\n        metric.register(\n                binRepository\n                        .countActiveWithPartsNumber()\n                        .toRangeMap()\n                        .map {\n                            MultiGauge.Row.of(\n                                    Tags.of(NUMBER_OF_EGGS_LABEL, it.key),\n                                    it.value\n                            )\n                        }, true);\n    }\n\n    private fun List<NumberOfBinsAndParts>.toRangeMap(): MutableMap<String, Long> {\n        var total = 0L;\n        val map = mutableMapOf<String, Long>();\n        numberOfEggsBuckets.forEach { map[it] = 0 };\n\n        this.forEach {\n            total += it.numberOfBins\n            when (it.numberOfParts) {\n                1 -> map[EGG_1_BUCKET_LABEL] = it.numberOfBins\n                2 -> map[EGG_2_BUCKET_LABEL] = it.numberOfBins\n                3 -> map[EGG_3_BUCKET_LABEL] = it.numberOfBins\n                in 4..5 -> map[EGG_4_5_BUCKET_LABEL] = it.numberOfBins\n                in 7..9 -> map[EGG_7_9_BUCKET_LABEL] = it.numberOfBins\n                in 10..Int.MAX_VALUE -> map[EGG_OVER_10_BUCKET_LABEL] = it.numberOfBins\n            };\n        };\n\n        map[ALL_ACTIVE_BINS_LABEL] = total;\n        return map;\n    }\n\n\n}"
  },
  {
    "path": "diktat-cli/src/test/resources/test/smoke/src/main/kotlin/kotlin-library-expected.gradle.kts",
    "content": "import org.gradle.kotlin.dsl.plugins\n// import org.jetbrains.kotlin.gradle.dsl.jvm\n\nplugins {\n    kotlin(\"jvm\")\n}\n"
  },
  {
    "path": "diktat-cli/src/test/resources/test/smoke/src/main/kotlin/kotlin-library.gradle.kts",
    "content": "import org.gradle.kotlin.dsl.plugins\n//import org.jetbrains.kotlin.gradle.dsl.jvm\n\nplugins {\n    kotlin(\"jvm\")\n}"
  },
  {
    "path": "diktat-cli/src/test/resources/test/smoke/src/main/kotlin/save.toml",
    "content": "[general]\nexecCmd=\"java -showversion -jar diktat.jar --log-level debug\"\ntags = [\"smokeTest\"]\ndescription = \"SmokeTest\"\nsuiteName = \"SmokeTest\"\nlanguage = \"Kotlin\"\nexpectedWarningsPattern = \"// ;warn:?(.*):(\\\\d*): (.+)\"\n\n[\"fix and warn\"]\n    [\"fix and warn\".fix]\n        execFlags=\"--mode fix\"\n    [\"fix and warn\".warn]\n        actualWarningsPattern = \"(\\\\w+\\\\..+):(\\\\d+):(\\\\d+): (\\\\[.*\\\\].*)$\"\n        exactWarningsMatch = false\n"
  },
  {
    "path": "diktat-cli/src/test/resources/test/smoke/src/main/kotlin/script/PackageInScriptExpected.kts",
    "content": "// ;warn:$line:1: [HEADER_MISSING_IN_NON_SINGLE_CLASS_FILE] files that contain multiple or no classes should contain description of what is inside of this file: there are 0 declared classes and/or objects (cannot be auto-corrected) (diktat-ruleset:header-comment)\npackage com.saveourtool.diktat.script\n\nrun {\n    // ;warn:5: [DEBUG_PRINT] use a dedicated logging library: found println() (cannot be auto-corrected) (diktat-ruleset:debug-print)\n    println(\"hello world!\")\n}\n\n// ;warn:$line:1: [MISSING_KDOC_ON_FUNCTION] all public, internal and protected functions should have Kdoc with proper tags: foo (cannot be auto-corrected) (diktat-ruleset:kdoc-methods)\nfun foo() {\n    // ;warn:5: [DEBUG_PRINT] use a dedicated logging library: found println() (cannot be auto-corrected) (diktat-ruleset:debug-print)\n    println()\n}\n\n// ;warn:5: [IDENTIFIER_LENGTH] identifier's length is incorrect, it should be in range of [2, 64] symbols: q (cannot be auto-corrected) (diktat-ruleset:identifier-naming)\nval q = Config()\n\nrun {\n    // ;warn:5: [DEBUG_PRINT] use a dedicated logging library: found println() (cannot be auto-corrected) (diktat-ruleset:debug-print)\n    println(\"a\")\n}\n\nalso {\n    // ;warn:5: [DEBUG_PRINT] use a dedicated logging library: found println() (cannot be auto-corrected) (diktat-ruleset:debug-print)\n    println(\"a\")\n}\n"
  },
  {
    "path": "diktat-cli/src/test/resources/test/smoke/src/main/kotlin/script/PackageInScriptTest.kts",
    "content": "package com.saveourtool.diktat.script\n\nrun {\n    println(\"hello world!\")\n}\n\nfun foo() {\n    println()\n}\n\nval q = Config()\n\nrun {\n    println(\"a\")\n}\n\nalso {\n    println(\"a\")\n}\n"
  },
  {
    "path": "diktat-cli/src/test/resources/test/smoke/src/main/kotlin/script/SimpleRunInScriptExpected.kts",
    "content": "// ;warn:$line:1: [HEADER_MISSING_IN_NON_SINGLE_CLASS_FILE] files that contain multiple or no classes should contain description of what is inside of this file: there are 0 declared classes and/or objects (cannot be auto-corrected) (diktat-ruleset:header-comment)\n\nrun {\n    // ;warn:5: [DEBUG_PRINT] use a dedicated logging library: found println() (cannot be auto-corrected) (diktat-ruleset:debug-print)\n    println(\"hello world!\")\n}\n\n// ;warn:$line:1: [MISSING_KDOC_ON_FUNCTION] all public, internal and protected functions should have Kdoc with proper tags: foo (cannot be auto-corrected) (diktat-ruleset:kdoc-methods)\nfun foo() {\n    // ;warn:5: [DEBUG_PRINT] use a dedicated logging library: found println() (cannot be auto-corrected) (diktat-ruleset:debug-print)\n    println()\n}\n\n// ;warn:5: [IDENTIFIER_LENGTH] identifier's length is incorrect, it should be in range of [2, 64] symbols: q (cannot be auto-corrected) (diktat-ruleset:identifier-naming)\nval q = Config()\n\nrun {\n    // ;warn:5: [DEBUG_PRINT] use a dedicated logging library: found println() (cannot be auto-corrected) (diktat-ruleset:debug-print)\n    println(\"a\")\n}\n\nalso {\n    // ;warn:5: [DEBUG_PRINT] use a dedicated logging library: found println() (cannot be auto-corrected) (diktat-ruleset:debug-print)\n    println(\"a\")\n}\n"
  },
  {
    "path": "diktat-cli/src/test/resources/test/smoke/src/main/kotlin/script/SimpleRunInScriptTest.kts",
    "content": "\nprintln(\"hello world!\")\n\nfun foo() {\n    println()\n}\n\nval q = Config()\n\nrun {\n    println(\"a\")\n}\n\nalso {\n    println(\"a\")\n}\n"
  },
  {
    "path": "diktat-common-test/build.gradle.kts",
    "content": "plugins {\n    id(\"com.saveourtool.diktat.buildutils.kotlin-jvm-configuration\")\n    id(\"com.saveourtool.diktat.buildutils.code-quality-convention\")\n    id(\"com.saveourtool.diktat.buildutils.publishing-default-configuration\")\n}\n\nproject.description = \"Diktat common for tests\"\n\ndependencies {\n    implementation(libs.kotlin.logging)\n    implementation(libs.junit.jupiter.api)\n    implementation(libs.assertj.core)\n}\n"
  },
  {
    "path": "diktat-common-test/src/main/kotlin/com/saveourtool/diktat/test/framework/processing/ResourceReader.kt",
    "content": "package com.saveourtool.diktat.test.framework.processing\n\nimport com.saveourtool.diktat.test.framework.util.readTextOrNull\nimport io.github.oshai.kotlinlogging.KotlinLogging\nimport java.nio.file.Path\nimport kotlin.io.path.createDirectories\nimport kotlin.io.path.isRegularFile\nimport kotlin.io.path.toPath\nimport kotlin.io.path.writeText\n\n/**\n * A base interface to read resources for testing purposes\n */\nfun interface ResourceReader : Function1<String, Path?> {\n    /**\n     * @param resourceName\n     * @return [Path] for provider [resourceName]\n     */\n    override fun invoke(resourceName: String): Path?\n\n    companion object {\n        private val log = KotlinLogging.logger {}\n\n        /**\n         * Default implementation of [ResourceReader]\n         */\n        val default: ResourceReader = ResourceReader { resourceName ->\n            ResourceReader::class.java\n                .classLoader\n                .getResource(resourceName)\n                ?.toURI()\n                ?.toPath()\n                .also { path ->\n                    if (path == null || !path.isRegularFile()) {\n                        log.error { \"Not able to find file for running test: $resourceName\" }\n                    }\n                }\n        }\n\n        /**\n         * @param tempDir the temporary directory (usually injected by _JUnit_).\n         * @param replacements a map of replacements which will be applied to actual and expected content before comparing.\n         * @return Instance of [ResourceReader] with replacements of content\n         */\n        fun ResourceReader.withReplacements(\n            tempDir: Path,\n            replacements: Map<String, String>,\n        ): ResourceReader = ResourceReader { resourceName ->\n            this@withReplacements.invoke(resourceName)\n                ?.let { originalFile ->\n                    tempDir.resolve(resourceName)\n                        .also { resultFile ->\n                            originalFile.readTextOrNull()?.replaceAll(replacements)\n                                ?.let {\n                                    resultFile.parent.createDirectories()\n                                    resultFile.writeText(it)\n                                }\n                        }\n                }\n        }\n\n        /**\n         * @param resourceFilePath a prefix for loading resources\n         * @return Instance of [ResourceReader] which loads resource with [resourceFilePath] as prefix\n         */\n        fun ResourceReader.withPrefix(\n            resourceFilePath: String,\n        ): ResourceReader = ResourceReader { resourceName -> this@withPrefix.invoke(\"$resourceFilePath/$resourceName\") }\n\n        private fun String.replaceAll(replacements: Map<String, String>): String = replacements.entries\n            .fold(this) { result, replacement ->\n                result.replace(replacement.key, replacement.value)\n            }\n    }\n}\n"
  },
  {
    "path": "diktat-common-test/src/main/kotlin/com/saveourtool/diktat/test/framework/processing/TestComparatorUnit.kt",
    "content": "package com.saveourtool.diktat.test.framework.processing\n\nimport com.saveourtool.diktat.test.framework.processing.ResourceReader.Companion.withPrefix\nimport com.saveourtool.diktat.test.framework.util.NEWLINE\nimport com.saveourtool.diktat.test.framework.util.readTextOrNull\nimport com.saveourtool.diktat.test.framework.util.toUnixEndLines\nimport io.github.oshai.kotlinlogging.KotlinLogging\nimport java.nio.file.Path\nimport kotlin.io.path.isRegularFile\n\n/**\n * Class that can apply transformation to an input file and then compare with expected result and output difference.\n *\n * @param resourceReader only used when the files are loaded as resources,\n *   via [compareFilesFromResources].\n * @param function a transformation that will be applied to the file\n */\n@Suppress(\"ForbiddenComment\", \"TYPE_ALIAS\")\nclass TestComparatorUnit(\n    private val resourceReader: ResourceReader = ResourceReader.default,\n    private val function: (testFile: Path) -> String,\n) {\n    constructor(\n        resourceFilePath: String,\n        function: (testFile: Path) -> String,\n    ) : this(\n        resourceReader = ResourceReader.default.withPrefix(resourceFilePath),\n        function = function,\n    )\n\n    /**\n     * @param expectedResult the name of the resource which has the expected\n     *   content. The trailing newline, if any, **won't be read** as a separate\n     *   empty string. So, if the content to be read from this file is expected\n     *   to be terminated with an empty string (which is the case if\n     *   `newlineAtEnd` is `true`), then the file should end with **two**\n     *   consecutive linebreaks.\n     * @param testFileStr the name of the resource which has the original content.\n     * @param overrideResourceReader function to override [ResourceReader] to read resource content\n     * @return the result of file comparison by their content.\n     * @see compareFilesFromFileSystem\n     */\n    @Suppress(\"FUNCTION_BOOLEAN_PREFIX\")\n    fun compareFilesFromResources(\n        expectedResult: String,\n        testFileStr: String,\n        overrideResourceReader: (ResourceReader) -> ResourceReader = { it },\n    ): TestFileContent {\n        val overriddenResourceReader = overrideResourceReader(resourceReader)\n        val expectedPath = overriddenResourceReader(expectedResult)\n        val testPath = overriddenResourceReader(testFileStr)\n        if (testPath == null || expectedPath == null) {\n            log.error { \"Not able to find files for running test: $expectedResult and $testFileStr\" }\n            return NotFoundResourcesTestFileContent(\n                expectedResource = expectedResult,\n                expectedPath = expectedPath,\n                actualResource = testFileStr,\n                actualPath = testPath,\n            )\n        }\n\n        return compareFilesFromFileSystem(\n            expectedPath,\n            testPath,\n        )\n    }\n\n    /**\n     * @param expectedFile the file which has the expected content. The trailing\n     *   newline, if any, **won't be read** as a separate empty string. So, if\n     *   the content to be read from this file is expected to be terminated with\n     *   an empty string (which is the case if `newlineAtEnd` is `true`), then\n     *   the file should end with **two** consecutive linebreaks.\n     * @param testFile the file which has the original content.\n     * @return the result of file comparison by their content.\n     * @see compareFilesFromResources\n     */\n    @Suppress(\"FUNCTION_BOOLEAN_PREFIX\")\n    fun compareFilesFromFileSystem(\n        expectedFile: Path,\n        testFile: Path,\n    ): TestFileContent {\n        if (!testFile.isRegularFile() || !expectedFile.isRegularFile()) {\n            log.error { \"Not able to find files for running test: $expectedFile and $testFile\" }\n            return NotFoundFilesTestFileContent(\n                expectedPath = expectedFile,\n                actualPath = testFile,\n            )\n        }\n\n        val actualFileContent = function(testFile).toUnixEndLines()\n        val expectedFileContent = expectedFile.readTextOrNull().orEmpty()\n\n        return DefaultTestFileContent(\n            actualContent = actualFileContent,\n            expectedContent = expectedFileContent.withoutWarns(),\n        )\n    }\n\n    private companion object {\n        private val log = KotlinLogging.logger {}\n        private val warnRegex = (\".*// ;warn:?(.*):(\\\\d*): (.+)\").toRegex()\n\n        /**\n         * @return Expected result without lines with warns\n         */\n        private fun String.withoutWarns(): String = split(NEWLINE)\n            .filterNot { line ->\n                line.contains(warnRegex)\n            }\n            .joinToString(NEWLINE.toString())\n    }\n}\n"
  },
  {
    "path": "diktat-common-test/src/main/kotlin/com/saveourtool/diktat/test/framework/processing/TestFileContent.kt",
    "content": "/**\n * It's a class container for test file content.\n * Plus exception cases when resource or file is not found\n */\n\npackage com.saveourtool.diktat.test.framework.processing\n\nimport com.saveourtool.diktat.test.framework.util.describe\n\nimport org.assertj.core.api.Assertions.assertThat\nimport org.assertj.core.api.SoftAssertions.assertSoftly\nimport org.intellij.lang.annotations.Language\n\nimport java.nio.file.Path\n\nimport kotlin.io.path.absolutePathString\n\n/**\n * A base interface for content of test file\n */\nsealed interface TestFileContent {\n    /**\n     * Asserts [TestFileContent] that content are equal\n     */\n    fun assertSuccessful()\n}\n\n/**\n * Implementation of [TestFileContent] when resources are not found\n *\n * @param expectedResource\n * @param expectedPath\n * @param actualResource\n * @param actualPath\n */\ndata class NotFoundResourcesTestFileContent(\n    private val expectedResource: String,\n    private val expectedPath: Path?,\n    private val actualResource: String,\n    private val actualPath: Path?,\n) : TestFileContent {\n    override fun assertSuccessful() {\n        assertSoftly { softly ->\n            softly.assertThat(expectedPath)\n                .describedAs(\"Expected resource <%s>\", expectedResource)\n                .isNotNull\n            softly.assertThat(actualPath)\n                .describedAs(\"Actual resource <%s>\", actualResource)\n                .isNotNull\n        }\n    }\n}\n\n/**\n * Implementation of [TestFileContent] when files are not found\n *\n * @param expectedPath\n * @param actualPath\n */\ndata class NotFoundFilesTestFileContent(\n    private val expectedPath: Path,\n    private val actualPath: Path,\n) : TestFileContent {\n    override fun assertSuccessful() {\n        assertSoftly { softly ->\n            softly.assertThat(expectedPath)\n                .describedAs(\"Expected file <%s>\", expectedPath.absolutePathString())\n                .isRegularFile\n            softly.assertThat(actualPath)\n                .describedAs(\"Actual resource <%s>\", actualPath.absolutePathString())\n                .isRegularFile\n        }\n    }\n}\n\n/**\n * The result of files being compared by their content.\n *\n * @param actualContent the actual file content (possibly slightly different\n *   from the original after `diktat:check` is run).\n * @param expectedContent the expected file content without warns.\n */\ndata class DefaultTestFileContent(\n    @Language(\"kotlin\") private val actualContent: String,\n    @Language(\"kotlin\") private val expectedContent: String,\n) : TestFileContent {\n    override fun assertSuccessful() {\n        assertThat(actualContent)\n            .describedAs(\"lint result for \", actualContent.describe())\n            .isEqualTo(expectedContent)\n    }\n}\n"
  },
  {
    "path": "diktat-common-test/src/main/kotlin/com/saveourtool/diktat/test/framework/util/TestUtils.kt",
    "content": "/**\n * Utility classes and methods for tests\n */\n\npackage com.saveourtool.diktat.test.framework.util\n\nimport io.github.oshai.kotlinlogging.KotlinLogging\n\nimport java.io.File\nimport java.io.IOException\nimport java.nio.charset.StandardCharsets\nimport java.nio.file.FileVisitResult\nimport java.nio.file.FileVisitResult.CONTINUE\nimport java.nio.file.Files\nimport java.nio.file.Files.walkFileTree\nimport java.nio.file.NoSuchFileException\nimport java.nio.file.Path\nimport java.nio.file.SimpleFileVisitor\nimport java.nio.file.attribute.BasicFileAttributes\nimport kotlin.contracts.ExperimentalContracts\nimport kotlin.contracts.contract\n\nimport kotlin.io.path.Path\nimport kotlin.io.path.absolute\nimport kotlin.io.path.absolutePathString\nimport kotlin.io.path.bufferedReader\nimport kotlin.io.path.createDirectories\nimport kotlin.io.path.deleteExisting\nimport kotlin.io.path.deleteIfExists\nimport kotlin.io.path.div\nimport kotlin.io.path.isDirectory\nimport kotlin.io.path.isSameFileAs\nimport kotlin.io.path.readText\n\nconst val NEWLINE = '\\n'\n\nprivate val logger = KotlinLogging.logger {}\n\n/**\n * Deletes the file if it exists, retrying as necessary if the file is\n * blocked by another process (on Windows).\n *\n * @receiver the file or empty directory.\n * @see Path.deleteIfExists\n */\n@Suppress(\n    \"EMPTY_BLOCK_STRUCTURE_ERROR\",\n    \"MAGIC_NUMBER\",\n)\nfun Path.deleteIfExistsSilently() {\n    val attempts = 10\n\n    val deleted = retry(attempts, delayMillis = 100L, lazyDefault = { false }) {\n        deleteIfExists()\n\n        /*\n         * Ignore the return code of `deleteIfExists()` (will be `false`\n         * if the file doesn't exist).\n         */\n        true\n    }\n\n    if (!deleted) {\n        logger.warn {\n            \"File \\\"${absolute()}\\\" not deleted after $attempts attempt(s).\"\n        }\n    }\n}\n\n/**\n * Deletes this directory recursively.\n *\n * @see Path.deleteIfExistsRecursively\n */\nfun Path.deleteRecursively() {\n    walkFileTree(this, object : SimpleFileVisitor<Path>() {\n        override fun visitFile(file: Path, attrs: BasicFileAttributes): FileVisitResult {\n            file.deleteIfExistsSilently()\n            return CONTINUE\n        }\n\n        override fun postVisitDirectory(dir: Path, exc: IOException?): FileVisitResult {\n            dir.deleteExisting()\n            return CONTINUE\n        }\n    })\n}\n\n/**\n * Deletes this directory recursively if it exists.\n *\n * @return `true` if the existing directory was successfully deleted, `false` if\n *   the directory doesn't exist.\n * @see Files.deleteIfExists\n * @see Path.deleteRecursively\n */\n@Suppress(\"FUNCTION_BOOLEAN_PREFIX\")\nfun Path.deleteIfExistsRecursively(): Boolean =\n    try {\n        deleteRecursively()\n        true\n    } catch (_: NoSuchFileException) {\n        false\n    }\n\n/**\n * @receiver the 1st operand.\n * @param other the 2nd operand.\n * @return `true` if, and only if, the two paths locate the same `JAVA_HOME`.\n */\nfun Path.isSameJavaHomeAs(other: Path): Boolean =\n    isDirectory() &&\n            (isSameFileAsSafe(other) ||\n                    resolve(\"jre\").isSameFileAsSafe(other) ||\n                    other.resolve(\"jre\").isSameFileAsSafe(this))\n\n/**\n * The same as [Path.isSameFileAs], but doesn't throw any [NoSuchFileException]\n * if either of the operands doesn't exist.\n *\n * @receiver the 1st operand.\n * @param other the 2nd operand.\n * @return `true` if, and only if, the two paths locate the same file.\n * @see Path.isSameFileAs\n */\nfun Path.isSameFileAsSafe(other: Path): Boolean =\n    try {\n        isSameFileAs(other)\n    } catch (_: NoSuchFileException) {\n        false\n    }\n\n/**\n * Requests that this file or directory be deleted when the JVM terminates.\n *\n * Does nothing if this [Path] is not associated with the default provider.\n *\n * @receiver a regular file or a directory.\n * @return this [Path].\n */\nfun Path.tryToDeleteOnExit(): Path {\n    try {\n        toFile().deleteOnExit()\n    } catch (_: UnsupportedOperationException) {\n        /*\n         * Ignore.\n         */\n    }\n\n    return this\n}\n\n/**\n * Resets any permissions which might otherwise prevent from reading or writing\n * this file or directory, or traversing this directory.\n *\n * @receiver a regular file or a directory.\n */\nfun Path.resetPermissions() {\n    toFile().apply {\n        setReadable(true)\n        setWritable(true)\n\n        if (isDirectory) {\n            setExecutable(true)\n        }\n    }\n}\n\n/**\n * Returns a sequence containing only files whose content (the first\n * [linesToRead] lines) matches [lineRegex].\n *\n * The operation is _intermediate_ and _stateless_.\n *\n * @receiver a sequence of regular files.\n * @param linesToRead the number of lines to read (at most).\n * @param lineRegex the regular expression to be applied to each line until a\n *   match is found (i.e. the line is found which _contains_ [lineRegex]).\n * @return the filtered sequence.\n */\nfun Sequence<Path>.filterContentMatches(linesToRead: Int, lineRegex: Regex): Sequence<Path> =\n    filter { file ->\n        file.bufferedReader().useLines { lines ->\n            lines.take(linesToRead).any { line ->\n                line.contains(lineRegex)\n            }\n        }\n    }\n\n/**\n * Prepends the `PATH` of this process builder with [pathEntry].\n *\n * @param pathEntry the entry to be prepended to the `PATH`.\n */\nfun ProcessBuilder.prependPath(pathEntry: Path) {\n    require(pathEntry.isDirectory()) {\n        \"$pathEntry is not a directory\"\n    }\n\n    val environment = environment()\n\n    val defaultPathKey = \"PATH\"\n    val defaultWindowsPathKey = \"Path\"\n\n    val pathKey = when {\n        /*-\n         * Keys of the Windows environment are case-insensitive (\"PATH\" == \"Path\").\n         * Keys of the Java interface to the environment are not (\"PATH\" != \"Path\").\n         * This is an attempt to work around the inconsistency.\n         */\n        System.getProperty(\"os.name\").isWindows() -> environment.keys.firstOrNull { key ->\n            key.equals(defaultPathKey, ignoreCase = true)\n        } ?: defaultWindowsPathKey\n\n        else -> defaultPathKey\n    }\n\n    val pathSeparator = File.pathSeparatorChar\n    val oldPath = environment[pathKey]\n\n    val newPath = when {\n        oldPath.isNullOrEmpty() -> pathEntry.toString()\n        else -> \"$pathEntry$pathSeparator$oldPath\"\n    }\n\n    environment[pathKey] = newPath\n}\n\n/**\n * Inherits the home of the current JVM (by setting `JAVA_HOME` and adding it to\n * the `PATH`) for the children of this process builder.\n */\nfun ProcessBuilder.inheritJavaHome() {\n    val javaHome = System.getProperty(\"java.home\")\n    environment()[\"JAVA_HOME\"] = javaHome\n    prependPath(Path(javaHome) / \"bin\")\n}\n\n/**\n * Changes the temporary directory for the children of this process builder.\n *\n * @param temporaryDirectory the new temporary directory (created automatically,\n *   scheduled for removal at JVM exit).\n */\nfun ProcessBuilder.temporaryDirectory(temporaryDirectory: Path) {\n    temporaryDirectory.createDirectories().tryToDeleteOnExit()\n\n    /*\n     * On UNIX, TMPDIR is the canonical name\n     */\n    val environmentVariables: Sequence<String> = when {\n        System.getProperty(\"os.name\").isWindows() -> sequenceOf(\"TMP\", \"TEMP\")\n        else -> sequenceOf(\"TMPDIR\")\n    }\n\n    val environment = environment()\n\n    val value = temporaryDirectory.absolutePathString()\n    environmentVariables.forEach { name ->\n        environment[name] = value\n    }\n}\n\n/**\n * @receiver the value of `os.name` system property.\n * @return `true` if the value of `os.name` system property starts with\n *   \"Windows\", `false` otherwise.\n */\n@OptIn(ExperimentalContracts::class)\nfun String?.isWindows(): Boolean {\n    contract {\n        returns(true) implies (this@isWindows != null)\n    }\n\n    return this != null && startsWith(\"Windows\")\n}\n\n/**\n * @return original [String] with unix end lines\n */\nfun String.toUnixEndLines(): String = replace(\"\\r\\n\", \"\\n\").replace(\"\\r\", \"\\n\")\n\n/**\n * @receiver the file whose content is to be read.\n * @return file content as a single [String], or null if an I/O error\n *   has occurred.\n */\nfun Path.readTextOrNull(): String? = try {\n    readText(StandardCharsets.UTF_8).toUnixEndLines()\n} catch (e: IOException) {\n    logger.error(e) { \"Not able to read file: $this\" }\n    null\n}\n\n/**\n * @return a brief description of this code fragment.\n */\nfun String.describe(): String {\n    val lines = splitToSequence(NEWLINE)\n\n    var first: String? = null\n\n    val count = lines.onEachIndexed { index, line ->\n        if (index == 0) {\n            first = line\n        }\n    }.count()\n\n    return when (count) {\n        1 -> \"\\\"$this\\\"\"\n        else -> \"\\\"$first\\u2026\\\" ($count line(s))\"\n    }\n}\n\n/**\n * Retries the execution of the [block].\n *\n * @param attempts the number of attempts (must be positive).\n * @param delayMillis the timeout (in milliseconds) between the consecutive\n *   attempts. The default is 0. Ignored if [attempts] is 1.\n * @param lazyDefault allows to override the return value if none of the\n *   attempts succeeds. By default, the last exception is thrown.\n * @param block the block to execute.\n * @return the result of the execution of the [block], or whatever [lazyDefault]\n *   evaluates to if none of the attempts is successful.\n */\nfun <T> retry(\n    attempts: Int,\n    delayMillis: Long = 0L,\n    lazyDefault: (Throwable) -> T = { error -> throw error },\n    block: () -> T\n): T {\n    require(attempts > 0) {\n        \"The number of attempts should be positive: $attempts\"\n    }\n\n    var lastError: Throwable? = null\n\n    repeat(attempts) {\n        try {\n            return block()\n        } catch (error: Throwable) {\n            lastError = error\n        }\n\n        if (delayMillis > 0L) {\n            @Suppress(\"SleepInsteadOfDelay\")\n            Thread.sleep(delayMillis)\n        }\n    }\n\n    return lazyDefault(lastError ?: Exception(\"The block was never executed\"))\n}\n\n/**\n * Checks whether the current JVM's home matches the `JAVA_HOME` environment\n * variable.\n */\n@Suppress(\"AVOID_NULL_CHECKS\")\nfun checkForkedJavaHome() {\n    val forkedJavaHome = System.getenv(\"JAVA_HOME\")\n    if (forkedJavaHome != null) {\n        val javaHome = System.getProperty(\"java.home\")\n        if (javaHome != null && !Path(javaHome).isSameJavaHomeAs(Path(forkedJavaHome))) {\n            logger.warn {\n                \"Current JDK home is $javaHome. Forked tests may use a different JDK at $forkedJavaHome.\"\n            }\n        }\n        logger.warn {\n            \"Make sure JAVA_HOME ($forkedJavaHome) points to a Java 8 or Java 11 home. Java 17 is not yet supported.\"\n        }\n    }\n}\n"
  },
  {
    "path": "diktat-dev-ksp/build.gradle.kts",
    "content": "plugins {\n    id(\"com.saveourtool.diktat.buildutils.kotlin-jvm-configuration\")\n    id(\"com.saveourtool.diktat.buildutils.code-quality-convention\")\n}\n\ndependencies {\n    implementation(libs.kotlin.ksp.api)\n}\n\nsequenceOf(\"diktatFix\", \"diktatCheck\").forEach { diktatTaskName ->\n    tasks.findByName(diktatTaskName)?.dependsOn(\n        tasks.named(\"compileKotlin\"),\n        tasks.named(\"processResources\"),\n    )\n}\n"
  },
  {
    "path": "diktat-dev-ksp/src/main/kotlin/com/saveourtool/diktat/ruleset/generation/EnumNames.kt",
    "content": "package com.saveourtool.diktat.ruleset.generation\n\n/**\n * Annotation that marks to generate an object with names from Enum\n *\n * @property generatedPackageName\n * @property generatedClassName\n */\n@Target(AnnotationTarget.CLASS)\n@Retention(AnnotationRetention.SOURCE)\nannotation class EnumNames(\n    val generatedPackageName: String,\n    val generatedClassName: String,\n)\n"
  },
  {
    "path": "diktat-dev-ksp/src/main/kotlin/com/saveourtool/diktat/ruleset/generation/EnumNamesSymbolProcessor.kt",
    "content": "package com.saveourtool.diktat.ruleset.generation\n\nimport com.google.devtools.ksp.processing.CodeGenerator\nimport com.google.devtools.ksp.processing.Dependencies\nimport com.google.devtools.ksp.processing.Resolver\nimport com.google.devtools.ksp.processing.SymbolProcessor\nimport com.google.devtools.ksp.symbol.ClassKind\nimport com.google.devtools.ksp.symbol.KSAnnotated\nimport com.google.devtools.ksp.symbol.KSAnnotation\nimport com.google.devtools.ksp.symbol.KSClassDeclaration\n\n/**\n * [SymbolProcessor] to generate a class with contacts for names from provided enum\n *\n * @param codeGenerator\n */\nclass EnumNamesSymbolProcessor(\n    private val codeGenerator: CodeGenerator,\n) : SymbolProcessor {\n    override fun process(resolver: Resolver): List<KSAnnotated> {\n        resolver.getEnumDeclarations().forEach { doProcess(resolver, it) }\n        return emptyList()\n    }\n\n    private fun doProcess(resolver: Resolver, enumDeclaration: KSClassDeclaration) {\n        val annotation = enumDeclaration.annotations\n            .single {\n                it.shortName.asString() == EnumNames::class.simpleName\n            }\n        val targetPackageName = annotation.getArgumentValue(\"generatedPackageName\")\n        val targetClassName = annotation.getArgumentValue(\"generatedClassName\")\n        if (resolver.isAlreadyGenerated(targetPackageName, targetClassName)) {\n            return\n        }\n        codeGenerator.createNewFile(\n            dependencies = Dependencies(false),\n            packageName = targetPackageName,\n            fileName = targetClassName,\n        ).bufferedWriter()\n            .use { writer ->\n                writer.write(autoGenerationComment)\n                writer.newLine()\n                writer.write(\"package $targetPackageName\\n\")\n                writer.newLine()\n                writer.write(\"import kotlin.String\\n\")\n                writer.newLine()\n                writer.write(\"object $targetClassName {\\n\")\n                enumDeclaration.declarations\n                    .filterIsInstance<KSClassDeclaration>()\n                    .filter { it.classKind == ClassKind.ENUM_ENTRY }\n                    .map { it.simpleName.asString() }\n                    .forEach { enumEntryName ->\n                        writer.write(\"    const val $enumEntryName: String = \\\"$enumEntryName\\\"\\n\")\n                    }\n                writer.write(\"}\\n\")\n            }\n    }\n\n    companion object {\n        /**\n         * The comment that will be added to the generated sources file.\n         */\n        private val autoGenerationComment =\n            \"\"\"\n                |/**\n                | * This document was auto generated, please don't modify it.\n                | * This document contains all enum properties from Warnings.kt as Strings.\n                | */\n            \"\"\".trimMargin()\n        private val annotationName: String = requireNotNull(EnumNames::class.qualifiedName) {\n            \"Failed to retrieve a qualified name from ${EnumNames::class}\"\n        }\n\n        private fun Resolver.getEnumDeclarations(): Sequence<KSClassDeclaration> = getSymbolsWithAnnotation(annotationName)\n            .filterIsInstance<KSClassDeclaration>()\n            .onEach { candidate ->\n                require(candidate.classKind == ClassKind.ENUM_CLASS) {\n                    \"Annotated class ${candidate.qualifiedName} is not enum\"\n                }\n            }\n\n        private fun KSAnnotation.getArgumentValue(argumentName: String): String = arguments\n            .singleOrNull { it.name?.asString() == argumentName }\n            .let { argument ->\n                requireNotNull(argument) {\n                    \"Not found $argumentName in $this\"\n                }\n            }\n            .value\n            ?.let { it as? String }\n            .let { argumentValue ->\n                requireNotNull(argumentValue) {\n                    \"Not found a value for $argumentName in $this\"\n                }\n            }\n\n        private fun Resolver.isAlreadyGenerated(\n            packageName: String,\n            className: String,\n        ): Boolean = getNewFiles()\n            .find { it.packageName.asString() == packageName && it.fileName == \"$className.kt\" }\n            ?.let { true }\n            ?: false\n    }\n}\n"
  },
  {
    "path": "diktat-dev-ksp/src/main/kotlin/com/saveourtool/diktat/ruleset/generation/EnumNamesSymbolProcessorProvider.kt",
    "content": "package com.saveourtool.diktat.ruleset.generation\n\nimport com.google.devtools.ksp.processing.SymbolProcessor\nimport com.google.devtools.ksp.processing.SymbolProcessorEnvironment\nimport com.google.devtools.ksp.processing.SymbolProcessorProvider\n\n/**\n * [SymbolProcessorProvider] for [EnumNamesSymbolProcessor]\n */\nclass EnumNamesSymbolProcessorProvider : SymbolProcessorProvider {\n    override fun create(\n        environment: SymbolProcessorEnvironment,\n    ): SymbolProcessor = EnumNamesSymbolProcessor(\n        codeGenerator = environment.codeGenerator,\n    )\n}\n"
  },
  {
    "path": "diktat-dev-ksp/src/main/resources/META-INF/services/com.google.devtools.ksp.processing.SymbolProcessorProvider",
    "content": "com.saveourtool.diktat.ruleset.generation.EnumNamesSymbolProcessorProvider\n"
  },
  {
    "path": "diktat-gradle-plugin/README.md",
    "content": "## Local testing\n\nYou can build and publish to maven local by using `gradlew :diktat-gradle-plugin:publishToMavenLocal`.\nThen you can use a built version in projects in examples.\nA calculated version will be printed in logs by `reckon` plugin.\n"
  },
  {
    "path": "diktat-gradle-plugin/build.gradle.kts",
    "content": "import com.saveourtool.diktat.buildutils.configurePom\n\nimport com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar\nimport org.gradle.nativeplatform.platform.internal.DefaultNativePlatform.getCurrentOperatingSystem\nimport org.jetbrains.kotlin.gradle.dsl.JvmTarget\nimport org.jetbrains.kotlin.gradle.dsl.KotlinVersion\nimport org.jetbrains.kotlin.gradle.tasks.KotlinCompile\n\n@Suppress(\"DSL_SCOPE_VIOLATION\", \"RUN_IN_SCRIPT\")  // https://github.com/gradle/gradle/issues/22797\nplugins {\n    id(\"com.saveourtool.diktat.buildutils.kotlin-jvm-configuration\")\n    id(\"com.saveourtool.diktat.buildutils.code-quality-convention\")\n    id(\"com.saveourtool.diktat.buildutils.publishing-configuration\")\n    id(\"pl.droidsonroids.jacoco.testkit\") version \"1.0.12\"\n    id(\"org.gradle.test-retry\") version \"1.5.8\"\n    id(\"com.gradle.plugin-publish\") version \"1.2.1\"\n    alias(libs.plugins.shadow)\n}\n\ndependencies {\n    implementation(kotlin(\"gradle-plugin-api\"))\n    implementation(projects.diktatRunner)\n    // merge sarif reports\n    implementation(libs.sarif4k.jvm)\n    implementation(libs.kotlinx.serialization.json)\n    testImplementation(libs.junit.jupiter.api)\n    testRuntimeOnly(libs.junit.jupiter.engine)\n    testImplementation(projects.diktatKtlintEngine)\n    testImplementation(libs.ktlint.cli.reporter.core)\n    testImplementation(libs.ktlint.cli.reporter.json)\n    testImplementation(libs.ktlint.cli.reporter.plain)\n    testImplementation(libs.ktlint.cli.reporter.sarif)\n}\n\ntasks.withType<KotlinCompile> {\n    compilerOptions {\n        // kotlin 1.4 api is the latest support version in kotlin 1.9\n        // min supported Gradle is 7.0\n        languageVersion.set(KotlinVersion.KOTLIN_2_0)\n        apiVersion.set(KotlinVersion.KOTLIN_2_0)\n        jvmTarget.set(JvmTarget.JVM_1_8)\n    }\n}\n\ntasks.named<ShadowJar>(\"shadowJar\") {\n    archiveClassifier.set(\"\")\n    duplicatesStrategy = DuplicatesStrategy.FAIL\n    // all kotlin libs\n    relocate(\"org.jetbrains\", \"shadow.org.jetbrains\")\n}\n\ngradlePlugin {\n    website = \"https://diktat.saveourtool.com/\"\n    vcsUrl = \"https://github.com/saveourtool/diktat\"\n    plugins {\n        create(\"diktatPlugin\") {\n            id = \"com.saveourtool.diktat\"\n            displayName = \"Static code analysis for Kotlin\"\n            description = \"Strict coding standard for Kotlin and a custom set of rules for detecting code smells, code style issues and bugs\"\n            tags = listOf(\"kotlin\", \"code-analysis\")\n            implementationClass = \"com.saveourtool.diktat.plugin.gradle.DiktatGradlePlugin\"\n        }\n    }\n}\n\nafterEvaluate {\n    publishing {\n        publications {\n            withType<MavenPublication> {\n                pom {\n                    configurePom(project)\n                }\n            }\n        }\n    }\n}\n\n// === testing & code coverage, jacoco is run independent from maven\nval functionalTestTask by tasks.register<Test>(\"functionalTest\")\ntasks.withType<Test> {\n    useJUnitPlatform()\n}\n\n// === integration testing\n// fixme: should probably use KotlinSourceSet instead\nval functionalTest: SourceSet = sourceSets.create(\"functionalTest\") {\n    compileClasspath += sourceSets.main.get().output + configurations.testRuntimeClasspath.get()\n    runtimeClasspath += output + compileClasspath\n}\n\n@Suppress(\"GENERIC_VARIABLE_WRONG_DECLARATION\", \"MAGIC_NUMBER\")\nval functionalTestProvider: TaskProvider<Test> = tasks.named<Test>(\"functionalTest\") {\n    shouldRunAfter(\"test\")\n    testClassesDirs = functionalTest.output.classesDirs\n    classpath = functionalTest.runtimeClasspath\n    maxParallelForks = Runtime.getRuntime().availableProcessors()\n    maxHeapSize = \"1024m\"\n    retry {\n        failOnPassedAfterRetry.set(false)\n        maxFailures.set(10)\n        maxRetries.set(3)\n    }\n    doLast {\n        if (getCurrentOperatingSystem().isWindows) {\n            // workaround for https://github.com/koral--/jacoco-gradle-testkit-plugin/issues/9\n            logger.lifecycle(\"Sleeping for 5 sec after functionalTest to avoid error with file locking\")\n            Thread.sleep(5_000)\n        }\n    }\n    finalizedBy(tasks.jacocoTestReport)\n}\ntasks.check { dependsOn(tasks.jacocoTestReport) }\n\njacocoTestKit {\n    @Suppress(\"UNCHECKED_CAST\")\n    applyTo(\"functionalTestRuntimeOnly\", functionalTestProvider as TaskProvider<Task>)\n}\ntasks.jacocoTestReport {\n    shouldRunAfter(tasks.withType<Test>())\n    executionData(\n        layout.buildDirectory\n            .dir(\"jacoco\")\n            .map { jacocoDir ->\n                jacocoDir.asFileTree\n                    .matching {\n                        include(\"*.exec\")\n                    }\n            }\n    )\n    reports {\n        // xml report is used by codecov\n        xml.required.set(true)\n    }\n}\n"
  },
  {
    "path": "diktat-gradle-plugin/src/functionalTest/kotlin/com/saveourtool/diktat/plugin/gradle/DiktatGradlePluginFunctionalTest.kt",
    "content": "package com.saveourtool.diktat.plugin.gradle\n\nimport com.saveourtool.diktat.plugin.gradle.DiktatGradlePlugin.Companion.DIKTAT_CHECK_TASK\nimport org.gradle.buildinit.plugins.internal.modifiers.BuildInitDsl\nimport org.gradle.internal.impldep.org.junit.rules.TemporaryFolder\nimport org.gradle.testkit.runner.TaskOutcome\nimport org.junit.jupiter.api.AfterEach\nimport org.junit.jupiter.api.Assertions\nimport org.junit.jupiter.api.BeforeEach\nimport org.junit.jupiter.api.Test\nimport java.io.File\n\nclass DiktatGradlePluginFunctionalTest {\n    private val testProjectDir = TemporaryFolder()\n    private lateinit var buildFile: File\n\n    @BeforeEach\n    fun setUp() {\n        testProjectDir.create()\n        val buildInitDsl = BuildInitDsl.KOTLIN\n        createExampleProject(testProjectDir, File(\"../examples/gradle-kotlin-dsl\"), buildInitDsl)\n        buildFile = testProjectDir.root.resolve(buildInitDsl.fileNameFor(\"build\"))\n    }\n\n    @AfterEach\n    fun tearDown() {\n        testProjectDir.delete()\n    }\n\n    @Test\n    fun `should execute diktatCheck on default values`() {\n        val result = runDiktat(testProjectDir, shouldSucceed = false)\n\n        val diktatCheckBuildResult = result.task(\":$DIKTAT_CHECK_TASK\")\n        requireNotNull(diktatCheckBuildResult)\n        Assertions.assertEquals(TaskOutcome.FAILED, diktatCheckBuildResult.outcome)\n        Assertions.assertTrue(\n            result.output.contains(\"[FILE_NAME_MATCH_CLASS]\")\n        )\n    }\n\n    @Test\n    fun `should have json reporter files`() {\n        buildFile.appendText(\n            \"\"\"${System.lineSeparator()}\n                diktat {\n                    inputs { include(\"src/**/*.kt\") }\n                    reporter = \"json\"\n                    output = \"test.txt\"\n                }\n            \"\"\".trimIndent()\n        )\n        val result = runDiktat(testProjectDir, shouldSucceed = false)\n\n        val diktatCheckBuildResult = result.task(\":$DIKTAT_CHECK_TASK\")\n        requireNotNull(diktatCheckBuildResult)\n        Assertions.assertEquals(TaskOutcome.FAILED, diktatCheckBuildResult.outcome)\n        val file = testProjectDir.root.walkTopDown().filter { it.name == \"test.txt\" }.first()\n        Assertions.assertNotNull(file)\n        Assertions.assertTrue(\n                file.readLines().any { it.contains(\"[FILE_NAME_MATCH_CLASS]\") }\n        )\n    }\n\n    @Test\n    fun `should execute diktatCheck with explicit inputs`() {\n        buildFile.appendText(\n            \"\"\"${System.lineSeparator()}\n                diktat {\n                    inputs { include(\"src/**/*.kt\") }\n                }\n            \"\"\".trimIndent()\n        )\n        val result = runDiktat(testProjectDir, shouldSucceed = false)\n\n        val diktatCheckBuildResult = result.task(\":$DIKTAT_CHECK_TASK\")\n        requireNotNull(diktatCheckBuildResult)\n        Assertions.assertEquals(TaskOutcome.FAILED, diktatCheckBuildResult.outcome)\n        Assertions.assertTrue(\n            result.output.contains(\"[FILE_NAME_MATCH_CLASS]\")\n        )\n    }\n\n    @Test\n    fun `should execute diktatCheck with excludes`() {\n        buildFile.appendText(\n            \"\"\"${System.lineSeparator()}\n                diktat {\n                    inputs {\n                        include(\"src/**/*.kt\")\n                        exclude(\"src/**/Test.kt\")\n                    }\n                }\n            \"\"\".trimIndent()\n        )\n        val result = runDiktat(testProjectDir, shouldSucceed = false)\n\n        val diktatCheckBuildResult = result.task(\":$DIKTAT_CHECK_TASK\")\n        requireNotNull(diktatCheckBuildResult)\n        Assertions.assertEquals(TaskOutcome.FAILED, diktatCheckBuildResult.outcome)\n    }\n\n    @Test\n    fun `should not run diktat with ktlint's default includes when no files match include patterns`() {\n        buildFile.appendText(\n            \"\"\"${System.lineSeparator()}\n                diktat {\n                    inputs { include (\"nonexistent-directory/src/**/*.kt\") }\n                }\n            \"\"\".trimIndent()\n        )\n        val result = runDiktat(testProjectDir, arguments = listOf(\"--info\"))\n\n        val diktatCheckBuildResult = result.task(\":$DIKTAT_CHECK_TASK\")\n        requireNotNull(diktatCheckBuildResult)\n        Assertions.assertEquals(TaskOutcome.NO_SOURCE, diktatCheckBuildResult.outcome)\n        Assertions.assertFalse(\n            result.output.contains(\"Skipping diktat execution\")\n        )\n    }\n\n    @Test\n    fun `should execute diktatCheck with gradle older than 6_4`() {\n        val result = runDiktat(testProjectDir, shouldSucceed = false, arguments = listOf(\"--info\")) {\n            withGradleVersion(\"5.3\")\n        }\n\n        val diktatCheckBuildResult = result.task(\":$DIKTAT_CHECK_TASK\")\n        requireNotNull(diktatCheckBuildResult)\n        Assertions.assertEquals(TaskOutcome.FAILED, diktatCheckBuildResult.outcome)\n        Assertions.assertTrue(\n            result.output.contains(\"[FILE_NAME_MATCH_CLASS]\")\n        )\n    }\n\n    @Test\n    fun `should respect ignoreFailures setting`() {\n        buildFile.appendText(\n            \"\"\"${System.lineSeparator()}\n                diktat {\n                    ignoreFailures = true\n                }\n            \"\"\".trimIndent()\n        )\n        val result = runDiktat(testProjectDir, shouldSucceed = true, arguments = listOf(\"--info\"))\n\n        val diktatCheckBuildResult = result.task(\":$DIKTAT_CHECK_TASK\")\n        requireNotNull(diktatCheckBuildResult)\n        Assertions.assertEquals(TaskOutcome.SUCCESS, diktatCheckBuildResult.outcome)\n        Assertions.assertTrue(\n            result.output.contains(\"[FILE_NAME_MATCH_CLASS]\")\n        )\n    }\n}\n"
  },
  {
    "path": "diktat-gradle-plugin/src/functionalTest/kotlin/com/saveourtool/diktat/plugin/gradle/DiktatGradlePluginGroovyFunctionalTest.kt",
    "content": "package com.saveourtool.diktat.plugin.gradle\n\nimport org.gradle.buildinit.plugins.internal.modifiers.BuildInitDsl\nimport org.gradle.internal.impldep.org.junit.rules.TemporaryFolder\nimport org.gradle.testkit.runner.TaskOutcome\nimport org.junit.jupiter.api.AfterEach\nimport org.junit.jupiter.api.Assertions\nimport org.junit.jupiter.api.BeforeEach\nimport org.junit.jupiter.api.Test\nimport java.io.File\n\nclass DiktatGradlePluginGroovyFunctionalTest {\n    private val testProjectDir = TemporaryFolder()\n    private lateinit var buildFile: File\n\n    @BeforeEach\n    fun setUp() {\n        testProjectDir.create()\n        val buildInitDsl = BuildInitDsl.GROOVY\n        createExampleProject(testProjectDir, File(\"../examples/gradle-groovy-dsl\"), buildInitDsl)\n        buildFile = testProjectDir.root.resolve(buildInitDsl.fileNameFor(\"build\"))\n    }\n\n    @AfterEach\n    fun tearDown() {\n        testProjectDir.delete()\n    }\n\n    @Test\n    fun `should execute diktatCheck with default values`() {\n        val result = runDiktat(testProjectDir, shouldSucceed = false)\n\n        assertDiktatExecuted(result)\n    }\n\n    @Test\n    fun `should execute diktatCheck with explicit configuration`() {\n        buildFile.appendText(\n            \"\"\"${System.lineSeparator()}\n                diktat {\n                    inputs { it.include(\"src/**/*.kt\") }\n                    reporter = \"plain\"\n                    diktatConfigFile = file(rootDir.path + \"/diktat-analysis.yml\")\n                }\n            \"\"\".trimIndent()\n        )\n\n        val result = runDiktat(testProjectDir, shouldSucceed = false)\n\n        assertDiktatExecuted(result)\n    }\n}\n"
  },
  {
    "path": "diktat-gradle-plugin/src/functionalTest/kotlin/com/saveourtool/diktat/plugin/gradle/DiktatGradlePluginMultiprojectFunctionalTest.kt",
    "content": "package com.saveourtool.diktat.plugin.gradle\n\nimport org.gradle.buildinit.plugins.internal.modifiers.BuildInitDsl\nimport org.gradle.internal.impldep.org.junit.rules.TemporaryFolder\nimport org.gradle.testkit.runner.TaskOutcome\nimport org.junit.jupiter.api.AfterEach\nimport org.junit.jupiter.api.BeforeEach\nimport org.junit.jupiter.api.Test\nimport java.io.File\n\nclass DiktatGradlePluginMultiprojectFunctionalTest {\n    private val testProjectDir = TemporaryFolder()\n    private lateinit var buildFile: File\n\n    @BeforeEach\n    fun setUp() {\n        testProjectDir.create()\n        val buildInitDsl = BuildInitDsl.KOTLIN\n        File(\"../examples/gradle-kotlin-dsl-multiproject\").copyRecursively(testProjectDir.root)\n        buildFile = testProjectDir.root.resolve(buildInitDsl.fileNameFor(\"build\"))\n    }\n\n    @AfterEach\n    fun tearDown() {\n        testProjectDir.delete()\n    }\n\n    @Test\n    fun `should execute diktatCheck on default values in multiproject build`() {\n        val result = runDiktat(testProjectDir, shouldSucceed = false)\n        assertDiktatExecuted(result, TaskOutcome.NO_SOURCE) {\n            \"Task for root project with empty sources should succeed\"\n        }\n    }\n}\n"
  },
  {
    "path": "diktat-gradle-plugin/src/functionalTest/kotlin/com/saveourtool/diktat/plugin/gradle/Utils.kt",
    "content": "package com.saveourtool.diktat.plugin.gradle\n\nimport org.gradle.buildinit.plugins.internal.modifiers.BuildInitDsl\nimport org.gradle.internal.impldep.org.junit.rules.TemporaryFolder\nimport org.gradle.testkit.runner.BuildResult\nimport org.gradle.testkit.runner.GradleRunner\nimport org.gradle.testkit.runner.TaskOutcome\nimport org.junit.jupiter.api.Assertions\nimport java.io.File\nimport java.util.concurrent.atomic.AtomicInteger\n\ninternal val testsCounter = AtomicInteger(0)\n\ninternal fun createExampleProject(testProjectDir: TemporaryFolder,\n                                  exampleProject: File,\n                                  buildInitDsl: BuildInitDsl\n) {\n    exampleProject.copyRecursively(testProjectDir.root)\n    val buildFileName = buildInitDsl.fileNameFor(\"build\")\n    File(testProjectDir.root, buildFileName).delete()\n    testProjectDir.newFile(buildFileName).writeText(\n        \"\"\"\n            plugins {\n                id(\"com.saveourtool.diktat\")\n            }\n\n            repositories {\n                mavenLocal()\n                mavenCentral()\n            }\n        \"\"\".trimIndent()\n    )\n}\n\n/**\n * @param arguments additional arguments to pass to [GradleRunner]\n */\ninternal fun runDiktat(testProjectDir: TemporaryFolder,\n                      shouldSucceed: Boolean = true,\n                      arguments: List<String> = emptyList(),\n                      configureRunner: GradleRunner.() -> GradleRunner = { this }\n) = GradleRunner.create()\n    .run(configureRunner)\n    .withProjectDir(testProjectDir.root)\n    .withArguments(arguments + DiktatGradlePlugin.DIKTAT_CHECK_TASK)\n    .withPluginClasspath()\n    .withJaCoCo(testsCounter.incrementAndGet())\n    .forwardOutput()\n    .runCatching {\n        if (shouldSucceed) build() else buildAndFail()\n    }\n    .also {\n        require(it.isSuccess) {\n            val ex = it.exceptionOrNull()\n            \"Running gradle returned exception $ex, cause: ${ex?.cause}\"\n        }\n    }\n    .getOrNull()\n    .let {\n        requireNotNull(it) {\n            \"Failed to get build result from running diktat\"\n        }\n    }\n\n/**\n * This is support for jacoco reports in tests run with gradle TestKit\n */\nprivate fun GradleRunner.withJaCoCo(number: Int) = apply {\n    javaClass.classLoader\n        .getResourceAsStream(\"testkit-gradle.properties\")\n        .also { it ?: error(\"properties file for testkit is not available, check build configuration\") }\n        ?.use { propertiesFileStream ->\n            val text = propertiesFileStream.reader().readText()\n            File(projectDir, \"gradle.properties\").createNewFile()\n            File(projectDir, \"gradle.properties\").writer().use {\n                it.write(text.replace(\"functionalTest.exec\", \"functionalTest-$number.exec\"))\n            }\n        }\n}\n\nfun assertDiktatExecuted(\n    result: BuildResult,\n    taskOutcome: TaskOutcome = TaskOutcome.FAILED,\n    errorMessage: () -> String? = { null }\n) {\n    val diktatCheckBuildResult = result.task(\":${DiktatGradlePlugin.DIKTAT_CHECK_TASK}\")\n    requireNotNull(diktatCheckBuildResult)\n    Assertions.assertEquals(taskOutcome, diktatCheckBuildResult.outcome, errorMessage)\n    Assertions.assertTrue(\n        result.output.contains(\"[FILE_NAME_MATCH_CLASS]\")\n    ) {\n        \"Task ${DiktatGradlePlugin.DIKTAT_CHECK_TASK} wasn't run\"\n    }\n}\n"
  },
  {
    "path": "diktat-gradle-plugin/src/main/kotlin/com/saveourtool/diktat/plugin/gradle/DiktatExtension.kt",
    "content": "package com.saveourtool.diktat.plugin.gradle\n\nimport com.saveourtool.diktat.plugin.gradle.extension.Reporters\nimport org.gradle.api.Action\nimport org.gradle.api.model.ObjectFactory\nimport org.gradle.api.tasks.InputFile\nimport org.gradle.api.tasks.Internal\nimport org.gradle.api.tasks.Optional\nimport org.gradle.api.tasks.PathSensitive\nimport org.gradle.api.tasks.PathSensitivity\nimport org.gradle.api.tasks.util.PatternFilterable\nimport org.gradle.api.tasks.util.PatternSet\nimport java.io.File\nimport javax.inject.Inject\n\n/**\n * An extension to configure diktat in build.gradle(.kts) file\n *\n * @param objectFactory\n * @param patternSet\n */\nopen class DiktatExtension @Inject constructor(\n    objectFactory: ObjectFactory,\n    private val patternSet: PatternSet,\n) {\n    /**\n     * All reporters\n     */\n    @get:Internal\n    val reporters: Reporters = objectFactory.newInstance(Reporters::class.java)\n\n    /**\n     * Boolean flag to support `ignoreFailures` property of [VerificationTask].\n     */\n    var ignoreFailures: Boolean = false\n\n    /**\n     * Flag that indicates whether to turn debug logging on\n     */\n    var debug = false\n\n    /**\n     * Property that will be used if you need to publish the report to GitHub\n     */\n    var githubActions = false\n\n    /**\n     * Baseline file, containing a list of errors that will be ignored.\n     * If this file doesn't exist, it will be created on the first invocation.\n     */\n    var baseline: String? = null\n\n    /**\n     * Path to diktat yml config file. Can be either absolute or relative to project's root directory.\n     * Default value: `diktat-analysis.yml` in rootDir if it exists or default (empty) configuration\n     */\n    @get:InputFile\n    @get:Optional\n    @get:PathSensitive(PathSensitivity.RELATIVE)\n    var diktatConfigFile: File? = null\n\n    /**\n     * Configure input files for diktat task\n     *\n     * @param action configuration lambda for `PatternFilterable`\n     */\n    fun inputs(action: PatternFilterable.() -> Unit) {\n        action(patternSet)\n    }\n\n    /**\n     * Configure reporters\n     *\n     * @param action configuration lambda for [Reporters]\n     */\n    fun reporters(action: Action<Reporters>): Unit = action.execute(reporters)\n}\n"
  },
  {
    "path": "diktat-gradle-plugin/src/main/kotlin/com/saveourtool/diktat/plugin/gradle/DiktatGradlePlugin.kt",
    "content": "package com.saveourtool.diktat.plugin.gradle\n\nimport com.saveourtool.diktat.plugin.gradle.tasks.DiktatCheckTask.Companion.registerDiktatCheckTask\nimport com.saveourtool.diktat.plugin.gradle.tasks.DiktatFixTask.Companion.registerDiktatFixTask\nimport com.saveourtool.diktat.plugin.gradle.tasks.configureMergeReportsTask\nimport org.gradle.api.Plugin\nimport org.gradle.api.Project\nimport org.gradle.api.tasks.util.PatternSet\n\n/**\n * Plugin that configures diktat and registers tasks to run diktat\n */\nclass DiktatGradlePlugin : Plugin<Project> {\n    /**\n     * @param project a gradle [Project] that the plugin is applied to\n     */\n    override fun apply(project: Project) {\n        val patternSet = PatternSet()\n        val diktatExtension = project.extensions.create(\n            DIKTAT_EXTENSION,\n            DiktatExtension::class.java,\n            patternSet,\n        ).apply {\n            diktatConfigFile = project.rootProject.file(\"diktat-analysis.yml\")\n        }\n\n        project.registerDiktatCheckTask(diktatExtension, patternSet)\n        project.registerDiktatFixTask(diktatExtension, patternSet)\n        project.configureMergeReportsTask()\n    }\n\n    companion object {\n        /**\n         * Task to check diKTat\n         */\n        const val DIKTAT_CHECK_TASK = \"diktatCheck\"\n\n        /**\n         * DiKTat extension\n         */\n        const val DIKTAT_EXTENSION = \"diktat\"\n\n        /**\n         * Task to run diKTat with fix\n         */\n        const val DIKTAT_FIX_TASK = \"diktatFix\"\n\n        /**\n         * Name of the task that merges SARIF reports of diktat tasks\n         */\n        internal const val MERGE_SARIF_REPORTS_TASK_NAME = \"mergeDiktatReports\"\n    }\n}\n"
  },
  {
    "path": "diktat-gradle-plugin/src/main/kotlin/com/saveourtool/diktat/plugin/gradle/Utils.kt",
    "content": "/**\n * Utilities for diktat gradle plugin\n */\n\npackage com.saveourtool.diktat.plugin.gradle\n\nimport org.gradle.api.Project\nimport org.gradle.api.file.RegularFile\nimport org.gradle.api.provider.Provider\nimport org.gradle.api.reporting.ReportingExtension\n\n/**\n * @param fileName\n * @param extension\n * @return default location of report with provided [extension]\n */\ninternal fun Project.defaultReportLocation(\n    extension: String,\n    fileName: String = \"diktat\",\n): Provider<RegularFile> = project.layout\n    .buildDirectory\n    .file(\"${ReportingExtension.DEFAULT_REPORTS_DIR_NAME}/diktat/$fileName.$extension\")\n"
  },
  {
    "path": "diktat-gradle-plugin/src/main/kotlin/com/saveourtool/diktat/plugin/gradle/extension/DefaultReporter.kt",
    "content": "/**\n * All default reporters\n */\n\n@file:Suppress(\"UnnecessaryAbstractClass\")\n\npackage com.saveourtool.diktat.plugin.gradle.extension\n\nimport com.saveourtool.diktat.api.DiktatReporterCreationArguments\nimport com.saveourtool.diktat.api.DiktatReporterType\nimport com.saveourtool.diktat.plugin.gradle.defaultReportLocation\nimport org.gradle.api.Project\nimport org.gradle.api.file.RegularFile\nimport org.gradle.api.file.RegularFileProperty\nimport org.gradle.api.model.ObjectFactory\nimport org.gradle.api.provider.Provider\nimport java.io.File\nimport java.nio.file.Files\nimport java.nio.file.Path\nimport javax.inject.Inject\n\n/**\n * A base interface for reporter\n *\n * @param objectFactory\n * @param project\n * @property type type of reporter\n */\nabstract class DefaultReporter @Inject constructor(\n    val type: DiktatReporterType,\n    objectFactory: ObjectFactory,\n    project: Project,\n) : Reporter {\n    override val output: RegularFileProperty = objectFactory.fileProperty()\n        .also { fileProperty ->\n            fileProperty.convention(project.defaultReportLocation(extension = type.extension))\n        }\n\n    override fun toCreationArguments(sourceRootDir: Path): DiktatReporterCreationArguments = DiktatReporterCreationArguments(\n        reporterType = type,\n        outputStream = output.map { file -> file.asFile.also { Files.createDirectories(it.parentFile.toPath()) }.outputStream() }.orNull,\n        sourceRootDir = sourceRootDir.takeIf { type == DiktatReporterType.SARIF },\n    )\n}\n\n/**\n * Plain reporter\n *\n * @param objectFactory\n * @param project\n */\nabstract class PlainReporter @Inject constructor(\n    objectFactory: ObjectFactory,\n    project: Project,\n) : DefaultReporter(\n    type = DiktatReporterType.PLAIN,\n    objectFactory,\n    project,\n) {\n    /**\n     * Remove the default value for plain to print to stdout by default\n     */\n    override val output: RegularFileProperty = objectFactory.fileProperty()\n        .also { fileProperty ->\n            fileProperty.set(null as File?)\n        }\n}\n\n/**\n * JSON reporter\n *\n * @param objectFactory\n * @param project\n */\nabstract class JsonReporter @Inject constructor(\n    objectFactory: ObjectFactory,\n    project: Project,\n) : DefaultReporter(\n    type = DiktatReporterType.JSON,\n    objectFactory,\n    project,\n)\n\n/**\n * SARIF reporter\n *\n * @param objectFactory\n * @param project\n */\nabstract class SarifReporter @Inject constructor(\n    objectFactory: ObjectFactory,\n    project: Project,\n) : DefaultReporter(\n    type = DiktatReporterType.SARIF,\n    objectFactory,\n    project,\n)\n\n/**\n * GitHub actions reporter\n *\n * @param objectFactory\n * @param project\n */\nabstract class GitHubActionsReporter @Inject constructor(\n    project: Project,\n    objectFactory: ObjectFactory,\n) : SarifReporter(objectFactory, project) {\n    override val output: RegularFileProperty = objectFactory.fileProperty()\n        .also { fileProperty ->\n            fileProperty.convention(project.getGitHubActionReporterOutput())\n                .finalizeValue()\n        }\n\n    /**\n     * Location for merged output\n     */\n    val mergeOutput: RegularFileProperty = objectFactory.fileProperty()\n        .also { fileProperty ->\n            fileProperty.convention(project.getGitHubActionReporterMergeOutput())\n                .finalizeValue()\n        }\n\n    companion object {\n        /**\n         * @return [RegularFile] for output\n         */\n        fun Project.getGitHubActionReporterOutput(): Provider<RegularFile> = defaultReportLocation(extension = \"sarif\")\n\n        /**\n         * @return [RegularFile] for mergeOutput\n         */\n        fun Project.getGitHubActionReporterMergeOutput(): Provider<RegularFile> =\n            rootProject.defaultReportLocation(fileName = \"diktat-merged\", extension = \"sarif\")\n    }\n}\n\n/**\n * Checkstyle reporter\n *\n * @param objectFactory\n * @param project\n */\nabstract class CheckstyleReporter @Inject constructor(\n    objectFactory: ObjectFactory,\n    project: Project,\n) : DefaultReporter(\n    type = DiktatReporterType.CHECKSTYLE,\n    objectFactory,\n    project,\n)\n\n/**\n * HTML reporter\n *\n * @param objectFactory\n * @param project\n */\nabstract class HtmlReporter @Inject constructor(\n    objectFactory: ObjectFactory,\n    project: Project,\n) : DefaultReporter(\n    type = DiktatReporterType.HTML,\n    objectFactory,\n    project,\n)\n"
  },
  {
    "path": "diktat-gradle-plugin/src/main/kotlin/com/saveourtool/diktat/plugin/gradle/extension/Reporter.kt",
    "content": "package com.saveourtool.diktat.plugin.gradle.extension\n\nimport com.saveourtool.diktat.api.DiktatReporterCreationArguments\nimport org.gradle.api.file.RegularFileProperty\nimport org.gradle.api.tasks.OutputFile\nimport java.nio.file.Path\n\n/**\n * A base interface for reporter\n */\ninterface Reporter {\n    /**\n     * Location for output\n     */\n    @get:OutputFile\n    val output: RegularFileProperty\n\n    /**\n     * @param sourceRootDir\n     * @return [DiktatReporterCreationArguments] to create this reporter\n     */\n    fun toCreationArguments(sourceRootDir: Path): DiktatReporterCreationArguments\n}\n"
  },
  {
    "path": "diktat-gradle-plugin/src/main/kotlin/com/saveourtool/diktat/plugin/gradle/extension/Reporters.kt",
    "content": "package com.saveourtool.diktat.plugin.gradle.extension\n\nimport org.gradle.api.Action\nimport org.gradle.api.model.ObjectFactory\nimport javax.inject.Inject\n\n/**\n * Configuration for reporters\n */\nopen class Reporters @Inject constructor(\n    private val objectFactory: ObjectFactory,\n) {\n    /**\n     * All reporters\n     */\n    val all: MutableList<Reporter> = mutableListOf()\n\n    /**\n     * Configure *plain* reporter with [action] configuration\n     *\n     * @param action\n     */\n    fun plain(action: Action<PlainReporter>): Unit = action.execute(newReporter())\n\n    /**\n     * Configure *plain* reporter with default configuration\n     */\n    fun plain() {\n        plain(emptyAction())\n    }\n\n    /**\n     * Configure *json* reporter with [action] configuration\n     *\n     * @param action\n     */\n    fun json(action: Action<JsonReporter>): Unit = action.execute(newReporter())\n\n    /**\n     * Configure *json* reporter with default configuration\n     */\n    fun json() {\n        json(emptyAction())\n    }\n\n    /**\n     * Configure *sarif* reporter with [action] configuration\n     *\n     * @param action\n     */\n    fun sarif(action: Action<SarifReporter>): Unit = action.execute(newReporter())\n\n    /**\n     * Configure *sarif* reporter with default configuration\n     */\n    fun sarif() {\n        sarif(emptyAction())\n    }\n\n    /**\n     * Configure *sarif* reporter for GitHub actions\n     */\n    fun gitHubActions() {\n        newReporter<GitHubActionsReporter>()\n    }\n\n    /**\n     * Configure *checkstyle* reporter with [action] configuration\n     *\n     * @param action\n     */\n    fun checkstyle(action: Action<CheckstyleReporter>): Unit = action.execute(newReporter())\n\n    /**\n     * Configure *checkstyle* reporter with default configuration\n     */\n    fun checkstyle() {\n        checkstyle(emptyAction())\n    }\n\n    /**\n     * Configure *html* reporter with default configuration\n     */\n    fun html() {\n        html(emptyAction())\n    }\n\n    /**\n     * Configure *html* reporter with [action] configuration\n     *\n     * @param action\n     */\n    fun html(action: Action<HtmlReporter>): Unit = action.execute(newReporter())\n\n    private inline fun <reified T : Reporter> newReporter(): T = objectFactory.newInstance(T::class.java)\n        .apply { all.add(this) }\n\n    private inline fun <reified T : Reporter> emptyAction() = Action<T> { }\n}\n"
  },
  {
    "path": "diktat-gradle-plugin/src/main/kotlin/com/saveourtool/diktat/plugin/gradle/tasks/DiktatCheckTask.kt",
    "content": "package com.saveourtool.diktat.plugin.gradle.tasks\n\nimport com.saveourtool.diktat.DiktatRunner\nimport com.saveourtool.diktat.DiktatRunnerArguments\nimport com.saveourtool.diktat.plugin.gradle.DiktatExtension\nimport com.saveourtool.diktat.plugin.gradle.DiktatGradlePlugin\nimport org.gradle.api.Project\nimport org.gradle.api.model.ObjectFactory\nimport org.gradle.api.tasks.TaskProvider\nimport org.gradle.api.tasks.util.PatternFilterable\nimport org.gradle.api.tasks.util.PatternSet\nimport javax.inject.Inject\n\n/**\n * A task to check source code by diktat\n */\nabstract class DiktatCheckTask @Inject constructor(\n    extension: DiktatExtension,\n    inputs: PatternFilterable,\n    objectFactory: ObjectFactory,\n) : DiktatTaskBase(\n    extension,\n    inputs,\n    objectFactory\n) {\n    override fun doRun(\n        runner: DiktatRunner,\n        args: DiktatRunnerArguments\n    ): Int = runner.checkAll(args)\n\n    companion object {\n        /**\n         * @param diktatExtension [DiktatExtension] with some values for task configuration\n         * @param patternSet [PatternSet] to discover files for diktat check\n         * @return a [TaskProvider]\n         */\n        fun Project.registerDiktatCheckTask(\n            diktatExtension: DiktatExtension,\n            patternSet: PatternSet,\n        ): TaskProvider<DiktatCheckTask> =\n            tasks.register(\n                DiktatGradlePlugin.DIKTAT_CHECK_TASK, DiktatCheckTask::class.java,\n                diktatExtension, patternSet,\n            ).also { it.configure(diktatExtension) }\n    }\n}\n"
  },
  {
    "path": "diktat-gradle-plugin/src/main/kotlin/com/saveourtool/diktat/plugin/gradle/tasks/DiktatFixTask.kt",
    "content": "package com.saveourtool.diktat.plugin.gradle.tasks\n\nimport com.saveourtool.diktat.DiktatRunner\nimport com.saveourtool.diktat.DiktatRunnerArguments\nimport com.saveourtool.diktat.plugin.gradle.DiktatExtension\nimport com.saveourtool.diktat.plugin.gradle.DiktatGradlePlugin\nimport org.gradle.api.Project\nimport org.gradle.api.model.ObjectFactory\nimport org.gradle.api.tasks.TaskProvider\nimport org.gradle.api.tasks.util.PatternFilterable\nimport org.gradle.api.tasks.util.PatternSet\nimport javax.inject.Inject\n\n/**\n * A task to check source code by diktat\n */\nabstract class DiktatFixTask @Inject constructor(\n    extension: DiktatExtension,\n    inputs: PatternFilterable,\n    objectFactory: ObjectFactory,\n) : DiktatTaskBase(\n    extension,\n    inputs,\n    objectFactory\n) {\n    override fun doRun(\n        runner: DiktatRunner,\n        args: DiktatRunnerArguments\n    ): Int = runner.fixAll(args) { updatedFile ->\n        project.logger.info(\"Original and formatted content differ, writing to ${updatedFile.fileName}...\")\n    }\n\n    companion object {\n        /**\n         * @param diktatExtension [DiktatExtension] with some values for task configuration\n         * @param patternSet [PatternSet] to discover files for diktat fix\n         * @return a [TaskProvider]\n         */\n        fun Project.registerDiktatFixTask(\n            diktatExtension: DiktatExtension,\n            patternSet: PatternSet,\n        ): TaskProvider<DiktatFixTask> =\n            tasks.register(\n                DiktatGradlePlugin.DIKTAT_FIX_TASK, DiktatFixTask::class.java,\n                diktatExtension, patternSet,\n            ).also { it.configure(diktatExtension) }\n    }\n}\n"
  },
  {
    "path": "diktat-gradle-plugin/src/main/kotlin/com/saveourtool/diktat/plugin/gradle/tasks/DiktatTaskBase.kt",
    "content": "package com.saveourtool.diktat.plugin.gradle.tasks\n\nimport com.saveourtool.diktat.DiktatRunner\nimport com.saveourtool.diktat.DiktatRunnerArguments\nimport com.saveourtool.diktat.DiktatRunnerFactory\nimport com.saveourtool.diktat.ENGINE_INFO\nimport com.saveourtool.diktat.api.DiktatProcessorListener\nimport com.saveourtool.diktat.api.DiktatReporterCreationArguments\nimport com.saveourtool.diktat.api.DiktatReporterType\nimport com.saveourtool.diktat.diktatRunnerFactory\nimport com.saveourtool.diktat.plugin.gradle.DiktatExtension\nimport com.saveourtool.diktat.plugin.gradle.extension.DefaultReporter\nimport com.saveourtool.diktat.plugin.gradle.extension.PlainReporter\nimport com.saveourtool.diktat.plugin.gradle.extension.Reporters\n\nimport generated.DIKTAT_VERSION\nimport org.gradle.api.DefaultTask\nimport org.gradle.api.GradleException\nimport org.gradle.api.file.ConfigurableFileCollection\nimport org.gradle.api.file.FileCollection\nimport org.gradle.api.file.RegularFileProperty\nimport org.gradle.api.model.ObjectFactory\nimport org.gradle.api.tasks.IgnoreEmptyDirectories\nimport org.gradle.api.tasks.InputFile\nimport org.gradle.api.tasks.InputFiles\nimport org.gradle.api.tasks.Internal\nimport org.gradle.api.tasks.Optional\nimport org.gradle.api.tasks.OutputFiles\nimport org.gradle.api.tasks.PathSensitive\nimport org.gradle.api.tasks.PathSensitivity\nimport org.gradle.api.tasks.SkipWhenEmpty\nimport org.gradle.api.tasks.TaskAction\nimport org.gradle.api.tasks.TaskProvider\nimport org.gradle.api.tasks.VerificationTask\nimport org.gradle.api.tasks.util.PatternFilterable\nimport org.gradle.language.base.plugins.LifecycleBasePlugin\n\nimport java.nio.file.Files\nimport java.nio.file.Path\n\n/**\n * A base task to run `diktat`\n *\n * @param inputs\n * @property extension\n */\n@Suppress(\"WRONG_NEWLINES\", \"Deprecation\")\nabstract class DiktatTaskBase(\n    @get:Internal internal val extension: DiktatExtension,\n    private val inputs: PatternFilterable,\n    objectFactory: ObjectFactory,\n) : DefaultTask(), VerificationTask {\n    /**\n     * Config file\n     */\n    @get:Optional\n    @get:InputFile\n    abstract val configFile: RegularFileProperty\n\n    /**\n     * Baseline\n     */\n    @get:Optional\n    @get:InputFile\n    abstract val baselineFile: RegularFileProperty\n\n    /**\n     * Files that will be analyzed by diktat\n     */\n    @get:IgnoreEmptyDirectories\n    @get:SkipWhenEmpty\n    @get:PathSensitive(PathSensitivity.RELATIVE)\n    @get:InputFiles\n    val actualInputs: FileCollection by lazy {\n        if (inputs.includes.isEmpty() && inputs.excludes.isEmpty()) {\n            inputs.include(\"src/**/*.kt\")\n        }\n        project.objects.fileCollection().from(\n            project.fileTree(\"${project.projectDir}\").apply {\n                exclude(\"${project.buildDir}\")\n            }\n                .matching(inputs)\n        )\n    }\n\n    /**\n     * All reporters\n     */\n    @get:Internal\n    val reporters: Reporters = objectFactory.newInstance(Reporters::class.java)\n\n    /**\n     * Outputs for all reporters\n     */\n    @get:OutputFiles\n    @get:Optional\n    val reporterOutputs: ConfigurableFileCollection = objectFactory.fileCollection()\n        .also { fileCollection ->\n            fileCollection.setFrom(reporters.all.mapNotNull { it.output.orNull })\n            fileCollection.finalizeValue()\n        }\n\n    /**\n     * Whether diktat should be executed\n     */\n    @get:Internal\n    internal val shouldRun: Boolean by lazy {\n        !actualInputs.isEmpty\n    }\n    private val diktatRunnerArguments by lazy {\n        val sourceRootDir by lazy {\n            project.rootProject.projectDir.toPath()\n        }\n        val defaultPlainReporter by lazy {\n            project.objects.newInstance(PlainReporter::class.java)\n        }\n        val reporterCreationArgumentsList = (reporters.all.takeUnless { it.isEmpty() } ?: listOf(defaultPlainReporter))\n            .filterIsInstance<DefaultReporter>()\n            .map { reporter ->\n                DiktatReporterCreationArguments(\n                    reporterType = reporter.type,\n                    outputStream = reporter.output.map { file -> file.asFile.also { Files.createDirectories(it.parentFile.toPath()) }.outputStream() }.orNull,\n                    sourceRootDir = sourceRootDir.takeIf { reporter.type == DiktatReporterType.SARIF },\n                )\n            }\n        val loggingListener = object : DiktatProcessorListener {\n            override fun beforeAll(files: Collection<Path>) {\n                project.logger.info(\"Analyzing {} files with diktat in project {}\", files.size, project.name)\n                project.logger.debug(\"Analyzing {}\", files)\n            }\n            override fun before(file: Path) {\n                project.logger.debug(\"Checking file {}\", file)\n            }\n        }\n        DiktatRunnerArguments(\n            configInputStream = configFile.map { it.asFile.inputStream() }.orNull,\n            sourceRootDir = sourceRootDir,\n            files = actualInputs.files.map { it.toPath() },\n            baselineFile = baselineFile.map { it.asFile.toPath() }.orNull,\n            reporterArgsList = reporterCreationArgumentsList,\n            loggingListener = loggingListener,\n        )\n    }\n\n    /**\n     * [DiktatRunner] created based on a default [DiktatRunnerFactory]\n     */\n    @get:Internal\n    val diktatRunner by lazy {\n        diktatRunnerFactory(diktatRunnerArguments)\n    }\n\n    init {\n        group = LifecycleBasePlugin.VERIFICATION_GROUP\n    }\n\n    /**\n     * Function to execute diKTat\n     *\n     * @throws GradleException\n     */\n    @TaskAction\n    fun run() {\n        if (extension.debug) {\n            project.logger.lifecycle(\"Running diktat $DIKTAT_VERSION with $ENGINE_INFO\")\n        }\n        if (!shouldRun) {\n            /*\n             If ktlint receives empty patterns, it implicitly uses &#42;&#42;/*.kt, **/*.kts instead.\n             This can lead to diktat analyzing gradle buildscripts and so on. We want to prevent it.\n             */\n            project.logger.warn(\"Inputs for $name do not exist, will not run diktat\")\n            project.logger.info(\"Skipping diktat execution\")\n        } else {\n            doRun()\n        }\n    }\n\n    private fun doRun() {\n        val errorCounter = doRun(\n            runner = diktatRunner,\n            args = diktatRunnerArguments\n        )\n        if (errorCounter > 0 && !ignoreFailures) {\n            throw GradleException(\"There are $errorCounter lint errors\")\n        }\n    }\n\n    /**\n     * An abstract method which should be overridden by fix and check tasks\n     *\n     * @param runner instance of [DiktatRunner] used in analysis\n     * @param args arguments for [DiktatRunner]\n     * @return count of errors\n     */\n    abstract fun doRun(\n        runner: DiktatRunner,\n        args: DiktatRunnerArguments\n    ): Int\n\n    companion object {\n        /**\n         * @param extension\n         */\n        fun TaskProvider<out DiktatTaskBase>.configure(extension: DiktatExtension) {\n            configure { task ->\n                extension.diktatConfigFile?.let { diktatConfigFile -> task.configFile.set(task.project.file(diktatConfigFile)) }\n                extension.baseline?.let { baseline -> task.baselineFile.set(task.project.file(baseline)) }\n                task.ignoreFailures = extension.ignoreFailures\n                task.reporters.all.addAll(extension.reporters.all)\n                if (extension.githubActions) {\n                    task.reporters.gitHubActions()\n                }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "diktat-gradle-plugin/src/main/kotlin/com/saveourtool/diktat/plugin/gradle/tasks/SarifReportMergeTask.kt",
    "content": "package com.saveourtool.diktat.plugin.gradle.tasks\n\nimport com.saveourtool.diktat.plugin.gradle.DiktatGradlePlugin.Companion.DIKTAT_CHECK_TASK\nimport com.saveourtool.diktat.plugin.gradle.DiktatGradlePlugin.Companion.MERGE_SARIF_REPORTS_TASK_NAME\nimport com.saveourtool.diktat.plugin.gradle.extension.GitHubActionsReporter.Companion.getGitHubActionReporterMergeOutput\nimport com.saveourtool.diktat.plugin.gradle.extension.GitHubActionsReporter.Companion.getGitHubActionReporterOutput\n\nimport io.github.detekt.sarif4k.SarifSchema210\nimport org.gradle.api.DefaultTask\nimport org.gradle.api.Project\nimport org.gradle.api.file.ConfigurableFileCollection\nimport org.gradle.api.file.RegularFileProperty\nimport org.gradle.api.tasks.InputFiles\nimport org.gradle.api.tasks.Optional\nimport org.gradle.api.tasks.OutputFile\nimport org.gradle.api.tasks.PathSensitive\nimport org.gradle.api.tasks.PathSensitivity\nimport org.gradle.api.tasks.TaskAction\nimport org.gradle.api.tasks.TaskExecutionException\nimport org.gradle.api.tasks.VerificationTask\n\nimport kotlinx.serialization.SerializationException\nimport kotlinx.serialization.encodeToString\nimport kotlinx.serialization.json.Json\n\n/**\n * A task to merge SARIF reports produced by diktat check / diktat fix tasks.\n */\nabstract class SarifReportMergeTask : DefaultTask(), VerificationTask {\n    /**\n     * Source reports that should be merged\n     */\n    @get:InputFiles\n    @get:PathSensitive(PathSensitivity.RELATIVE)\n    @get:Optional\n    abstract val input: ConfigurableFileCollection\n\n    /**\n     * Destination for the merged report\n     */\n    @get:OutputFile\n    @get:Optional\n    abstract val output: RegularFileProperty\n\n    /**\n     * @throws TaskExecutionException if failed to deserialize SARIF\n     */\n    @TaskAction\n    fun mergeReports() {\n        if (!output.isPresent) {\n            logger.debug(\"Skipping merging SARIF reports because output is not set\")\n            return\n        }\n        val sarifReports = input.files\n            .filter { it.exists() }\n            .also { logger.info(\"Merging SARIF reports from files $it\") }\n            .map {\n                try {\n                    Json.decodeFromString<SarifSchema210>(it.readText())\n                } catch (e: SerializationException) {\n                    logger.error(\"Couldn't deserialize JSON: is ${it.canonicalPath} a SARIF file?\")\n                    throw TaskExecutionException(this, e)\n                }\n            }\n\n        if (sarifReports.isEmpty()) {\n            logger.warn(\"Cannot perform merging of SARIF reports because no matching files were found; \" +\n                    \"is SARIF reporter active?\"\n            )\n            return\n        }\n\n        // All reports should contain identical metadata, so we are using the first one as a base.\n        val templateReport = sarifReports.first()\n        val allResults = sarifReports.flatMap { sarifSchema ->\n            sarifSchema.runs\n                .flatMap { it.results.orEmpty() }\n        }\n        val mergedSarif = templateReport.copy(\n            runs = listOf(templateReport.runs.first().copy(results = allResults))\n        )\n\n        output.get().asFile.writeText(Json.encodeToString(mergedSarif))\n    }\n}\n\n/**\n * Configure [MERGE_SARIF_REPORTS_TASK_NAME]\n */\ninternal fun Project.configureMergeReportsTask() {\n    val diktatCheckTask = tasks.named(DIKTAT_CHECK_TASK, DiktatCheckTask::class.java)\n    val rootMergeSarifReportsTask = if (path == rootProject.path) {\n        tasks.register(MERGE_SARIF_REPORTS_TASK_NAME, SarifReportMergeTask::class.java) { reportMergeTask ->\n            reportMergeTask.output.set(getGitHubActionReporterMergeOutput())\n        }\n    } else {\n        rootProject.tasks.named(MERGE_SARIF_REPORTS_TASK_NAME, SarifReportMergeTask::class.java)\n    }\n\n    rootMergeSarifReportsTask.configure { reportMergeTask ->\n        reportMergeTask.input.from(getGitHubActionReporterOutput())\n        reportMergeTask.mustRunAfter(diktatCheckTask)\n    }\n    diktatCheckTask.configure {\n        it.finalizedBy(rootMergeSarifReportsTask)\n    }\n}\n"
  },
  {
    "path": "diktat-gradle-plugin/src/test/kotlin/com/saveourtool/diktat/plugin/gradle/DiktatGradlePluginTest.kt",
    "content": "package com.saveourtool.diktat.plugin.gradle\n\nimport com.saveourtool.diktat.plugin.gradle.tasks.DiktatCheckTask\nimport org.gradle.api.Project\nimport org.gradle.testfixtures.ProjectBuilder\nimport org.junit.jupiter.api.Assertions\nimport org.junit.jupiter.api.BeforeEach\nimport org.junit.jupiter.api.Test\n\nclass DiktatGradlePluginTest {\n    private val projectBuilder = ProjectBuilder.builder()\n    private lateinit var project: Project\n\n    @BeforeEach\n    fun setUp() {\n        project = projectBuilder.build()\n        // mock kotlin sources\n        project.mkdir(\"src/main/kotlin\")\n        project.file(\"src/main/kotlin/Test.kt\").createNewFile()\n        project.pluginManager.apply(DiktatGradlePlugin::class.java)\n    }\n\n    @Test\n    fun `check that tasks are registered`() {\n        Assertions.assertTrue(project.tasks.findByName(\"diktatCheck\") != null)\n        Assertions.assertTrue(project.tasks.findByName(\"diktatFix\") != null)\n    }\n\n    @Test\n    fun `check default extension properties`() {\n        val diktatExtension = project.extensions.getByName(\"diktat\") as DiktatExtension\n        val actualInputs = project.tasks\n            .named(\"diktatCheck\", DiktatCheckTask::class.java)\n            .get()\n            .actualInputs\n        Assertions.assertFalse(diktatExtension.debug)\n        Assertions.assertIterableEquals(project.fileTree(\"src\").files, actualInputs.files)\n        Assertions.assertTrue(actualInputs.files.isNotEmpty())\n    }\n}\n"
  },
  {
    "path": "diktat-gradle-plugin/src/test/kotlin/com/saveourtool/diktat/plugin/gradle/DiktatJavaExecTaskTest.kt",
    "content": "package com.saveourtool.diktat.plugin.gradle\n\nimport com.saveourtool.diktat.api.DiktatReporter\nimport com.saveourtool.diktat.ktlint.DiktatReporterImpl.Companion.unwrapToKtlint\nimport com.saveourtool.diktat.plugin.gradle.tasks.DiktatCheckTask\nimport com.saveourtool.diktat.util.DiktatProcessorListenerWrapper.Companion.unwrap\nimport com.pinterest.ktlint.cli.reporter.json.JsonReporter\nimport com.pinterest.ktlint.cli.reporter.plain.PlainReporter\nimport com.pinterest.ktlint.cli.reporter.sarif.SarifReporter\n\nimport org.gradle.api.Project\nimport org.gradle.testfixtures.ProjectBuilder\nimport org.junit.jupiter.api.AfterEach\nimport org.junit.jupiter.api.Assertions\nimport org.junit.jupiter.api.BeforeEach\nimport org.junit.jupiter.api.Test\nimport java.io.File\nimport java.nio.file.Files\n\nclass DiktatJavaExecTaskTest {\n    private val projectBuilder = ProjectBuilder.builder()\n    private lateinit var project: Project\n\n    @BeforeEach\n    fun setUp() {\n        project = projectBuilder\n            .withName(\"testProject\")\n            .build()\n        // mock kotlin sources\n        project.mkdir(\"src/main/kotlin\")\n        project.file(\"src/main/kotlin/Test.kt\").createNewFile()\n        sequenceOf(\n            project.file(\"diktat-analysis.yml\"),\n            project.file(\"../diktat-analysis.yml\")\n        ).forEach {\n            it.writeText(\"\"\"\n                # Common configuration\n                - name: DIKTAT_COMMON\n                  enabled: true\n            \"\"\".trimIndent())\n        }\n    }\n\n    @AfterEach\n    fun tearDown() {\n        project.layout.buildDirectory.get().asFile.deleteRecursively()\n    }\n\n    @Test\n    fun `check command line for various inputs`() {\n        assertFiles(\n            listOf(\n                combinePathParts(\"src\", \"main\", \"kotlin\", \"Test.kt\")\n            )\n        ) {\n            inputs { include(\"src/**/*.kt\") }\n        }\n\n        val task = project.tasks.getByName(DIKTAT_CHECK_TASK) as DiktatCheckTask\n        assert(task.diktatRunner.diktatReporter.unwrapFirst() is PlainReporter)\n    }\n\n    @Test\n    fun `check command line in debug mode`() {\n        assertFiles(\n            listOf(combinePathParts(\"src\", \"main\", \"kotlin\", \"Test.kt\"))\n        ) {\n            inputs { include(\"src/**/*.kt\") }\n            debug = true\n        }\n    }\n\n    @Test\n    fun `check command line with excludes`() {\n        project.file(\"src/main/kotlin/generated\").mkdirs()\n        project.file(\"src/main/kotlin/generated/Generated.kt\").createNewFile()\n        assertFiles(\n            listOf(combinePathParts(\"src\", \"main\", \"kotlin\", \"Test.kt\"))\n        ) {\n            inputs {\n                include(\"src/**/*.kt\")\n                exclude(\"src/main/kotlin/generated\")\n            }\n        }\n\n        val task = project.tasks.getByName(DIKTAT_CHECK_TASK) as DiktatCheckTask\n        assert(task.diktatRunner.diktatReporter.unwrapFirst() is PlainReporter)\n    }\n\n    @Test\n    fun `check command line with non-existent inputs`() {\n        val task = project.registerDiktatTask {\n            inputs { exclude(\"*\") }\n        }\n        Assertions.assertFalse(task.shouldRun)\n    }\n\n    @Test\n    fun `check system property with default config`() {\n        val task = project.registerDiktatTask {\n            inputs { exclude(\"*\") }\n        }\n        Assertions.assertEquals(File(project.projectDir, \"diktat-analysis.yml\"), task.extension.diktatConfigFile)\n    }\n\n    @Test\n    fun `check system property with custom config`() {\n        val task = project.registerDiktatTask {\n            inputs { exclude(\"*\") }\n            diktatConfigFile = project.file(\"../diktat-analysis.yml\")\n        }\n        Assertions.assertEquals(File(project.projectDir.parentFile, \"diktat-analysis.yml\"), task.extension.diktatConfigFile)\n    }\n\n    @Test\n    fun `check command line has reporter type and output`() {\n        assertFiles(emptyList()) {\n            inputs { exclude(\"*\") }\n            diktatConfigFile = project.file(\"../diktat-analysis.yml\")\n            reporters { reportersDsl ->\n                reportersDsl.json { jsonDsl ->\n                    jsonDsl.output.set(project.layout.buildDirectory.file(\"some.txt\"))\n                }\n            }\n        }\n        val task = project.tasks.getByName(DIKTAT_CHECK_TASK) as DiktatCheckTask\n        assert(task.diktatRunner.diktatReporter.unwrapFirst() is JsonReporter)\n    }\n\n    @Test\n    fun `check command line has reporter type without output`() {\n        assertFiles(emptyList()) {\n            inputs { exclude(\"*\") }\n            diktatConfigFile = project.file(\"../diktat-analysis.yml\")\n            reporters { reportersDsl ->\n                reportersDsl.json()\n            }\n        }\n        val task = project.tasks.getByName(DIKTAT_CHECK_TASK) as DiktatCheckTask\n        assert(task.diktatRunner.diktatReporter.unwrapFirst() is JsonReporter)\n    }\n\n    @Test\n    fun `check command line in githubActions mode`() {\n        assertFiles(emptyList()) {\n            inputs { exclude(\"*\") }\n            diktatConfigFile = project.file(\"../diktat-analysis.yml\")\n            githubActions = true\n        }\n        val task = project.tasks.getByName(DIKTAT_CHECK_TASK) as DiktatCheckTask\n        assert(task.diktatRunner.diktatReporter.unwrapFirst() is SarifReporter)\n        Assertions.assertEquals(\n            project.rootDir.toString(),\n            System.getProperty(\"user.home\")\n        )\n    }\n\n    @Test\n    fun `githubActions mode should have higher precedence over explicit reporter`() {\n        assertFiles(emptyList()) {\n            inputs { exclude(\"*\") }\n            diktatConfigFile = project.file(\"../diktat-analysis.yml\")\n            githubActions = true\n            reporters { reportersDsl ->\n                reportersDsl.json { jsonDsl ->\n                    jsonDsl.output.set(project.layout.buildDirectory.file(\"report.json\"))\n                }\n            }\n        }\n        val task = project.tasks.getByName(DIKTAT_CHECK_TASK) as DiktatCheckTask\n        val (first, second) = task.diktatRunner.diktatReporter\n            .unwrap<Iterable<DiktatReporter>>()\n            .first()\n            .unwrap<DiktatReporter>()\n            .unwrap<Iterable<DiktatReporter>>()\n            .toList()\n\n        assert(first.unwrapToKtlint() is JsonReporter)\n        assert(second.unwrapToKtlint() is SarifReporter)\n\n        Assertions.assertEquals(\n            project.rootDir.toString(),\n            System.getProperty(\"user.home\")\n        )\n    }\n\n    @Test\n    fun `should set system property with SARIF reporter`() {\n        assertFiles(emptyList()) {\n            inputs { exclude(\"*\") }\n            diktatConfigFile = project.file(\"../diktat-analysis.yml\")\n            reporters { reportersDsl ->\n                reportersDsl.sarif()\n            }\n        }\n        val task = project.tasks.getByName(DIKTAT_CHECK_TASK) as DiktatCheckTask\n        assert(task.diktatRunner.diktatReporter.unwrapFirst() is SarifReporter)\n        Assertions.assertEquals(\n            project.rootProject.projectDir.toPath().toString(),\n            System.getProperty(\"user.home\")\n        )\n    }\n\n    @Test\n    fun `check system property with multiproject build with default config`() {\n        setupMultiProject()\n        val subproject = project.subprojects.first()\n        project.allprojects {\n            it.registerDiktatTask {\n                inputs { exclude(\"*\") }\n            }\n        }\n        val task = project.tasks.getByName(DIKTAT_CHECK_TASK) as DiktatCheckTask\n        val subprojectTask = subproject.tasks.getByName(DIKTAT_CHECK_TASK) as DiktatCheckTask\n        Assertions.assertEquals(File(project.projectDir, \"diktat-analysis.yml\"), task.extension.diktatConfigFile)\n        Assertions.assertEquals(File(project.projectDir, \"diktat-analysis.yml\"), subprojectTask.extension.diktatConfigFile)\n    }\n\n    @Test\n    fun `check system property with multiproject build with custom config`() {\n        setupMultiProject()\n        val subproject = project.subprojects.first()\n        project.allprojects {\n            it.registerDiktatTask {\n                inputs { exclude(\"*\") }\n                diktatConfigFile = it.rootProject.file(\"diktat-analysis.yml\")\n            }\n        }\n        val task = project.tasks.getByName(DIKTAT_CHECK_TASK) as DiktatCheckTask\n        val subprojectTask = subproject.tasks.getByName(DIKTAT_CHECK_TASK) as DiktatCheckTask\n        Assertions.assertEquals(File(project.projectDir, \"diktat-analysis.yml\"), task.extension.diktatConfigFile)\n        Assertions.assertEquals(File(project.projectDir, \"diktat-analysis.yml\"), subprojectTask.extension.diktatConfigFile)\n    }\n\n    @Test\n    fun `check system property with multiproject build with custom config and two config files`() {\n        setupMultiProject()\n        val subproject = project.subprojects.single()\n        subproject.file(\"diktat-analysis.yml\").createNewFile()\n        project.allprojects {\n            it.registerDiktatTask {\n                inputs { exclude(\"*\") }\n                diktatConfigFile = it.file(\"diktat-analysis.yml\")\n            }\n        }\n        val task = project.tasks.getByName(DIKTAT_CHECK_TASK) as DiktatCheckTask\n        val subprojectTask = subproject.tasks.getByName(DIKTAT_CHECK_TASK) as DiktatCheckTask\n        Assertions.assertEquals(File(project.projectDir, \"diktat-analysis.yml\"), task.extension.diktatConfigFile)\n        Assertions.assertEquals(File(subproject.projectDir, \"diktat-analysis.yml\"), subprojectTask.extension.diktatConfigFile)\n    }\n\n    private fun Project.registerDiktatTask(extensionConfiguration: DiktatExtension.() -> Unit): DiktatCheckTask {\n        pluginManager.apply(DiktatGradlePlugin::class.java)\n        extensions.configure(\"diktat\", extensionConfiguration)\n        return tasks.getByName(DIKTAT_CHECK_TASK) as DiktatCheckTask\n    }\n\n    private fun assertFiles(expected: List<String>, extensionConfiguration: DiktatExtension.() -> Unit) {\n        val task = project.registerDiktatTask(extensionConfiguration)\n        val files = task.actualInputs.files\n        Assertions.assertEquals(expected.size, files.size)\n        Assertions.assertTrue {\n            expected.zip(files)\n                .map { (expectedStr, file) ->\n                    file.path.endsWith(expectedStr)\n                }\n                .all { it }\n        }\n    }\n\n    private fun setupMultiProject() {\n        ProjectBuilder.builder()\n            .withParent(project)\n            .withName(\"testSubproject\")\n            .withProjectDir(File(project.projectDir, \"testSubproject\").also {\n                Files.createDirectory(it.toPath())\n            })\n            .build()\n        project.file(\"diktat-analysis.yml\").createNewFile()\n    }\n\n    private fun combinePathParts(vararg parts: String) = parts.joinToString(File.separator)\n\n    companion object {\n        private const val DIKTAT_CHECK_TASK = \"diktatCheck\"\n\n        private fun DiktatReporter.unwrapFirst() = this\n            .unwrap<Iterable<DiktatReporter>>().first()\n            .unwrap<DiktatReporter>()\n            .unwrap<Iterable<DiktatReporter>>().first()\n            .unwrapToKtlint()\n    }\n}\n"
  },
  {
    "path": "diktat-ktlint-engine/build.gradle.kts",
    "content": "import org.gradle.accessors.dm.LibrariesForLibs\n\nplugins {\n    id(\"com.saveourtool.diktat.buildutils.kotlin-jvm-configuration\")\n    id(\"com.saveourtool.diktat.buildutils.code-quality-convention\")\n    id(\"com.saveourtool.diktat.buildutils.publishing-default-configuration\")\n}\n\nproject.description = \"This module builds diktat-api implementation using ktlint\"\n\ndependencies {\n    api(projects.diktatApi)\n    implementation(libs.ktlint.cli.reporter.core)\n    implementation(libs.ktlint.rule.engine)\n    implementation(libs.ktlint.rule.engine.core)\n    implementation(libs.ktlint.cli.reporter.baseline)\n    implementation(libs.ktlint.cli.reporter.checkstyle)\n    implementation(libs.ktlint.cli.reporter.html)\n    implementation(libs.ktlint.cli.reporter.json)\n    implementation(libs.ktlint.cli.reporter.plain)\n    implementation(libs.ktlint.cli.reporter.sarif)\n\n    testImplementation(libs.log4j2.slf4j2)\n    testImplementation(libs.junit.jupiter)\n    testImplementation(libs.junit.platform.suite)\n    testImplementation(libs.assertj.core)\n}\n\nval ktlintVersion: String = the<LibrariesForLibs>()\n    .versions\n    .ktlint\n    .get()\n\nval generateKtlintVersionFile by tasks.registering {\n    val outputDir = layout.buildDirectory.dir(\"generated/src\").get().asFile\n    val versionsFile = outputDir.resolve(\"generated/KtLintVersion.kt\")\n\n    inputs.property(\"ktlint version\", ktlintVersion)\n    outputs.dir(outputDir)\n\n    doFirst {\n        versionsFile.parentFile.mkdirs()\n        versionsFile.writeText(\n            \"\"\"\n            package generated\n\n            const val KTLINT_VERSION = \"$ktlintVersion\"\n\n            \"\"\".trimIndent()\n        )\n    }\n}\n\nkotlin.sourceSets.getByName(\"main\") {\n    kotlin.srcDir(\n        generateKtlintVersionFile.map {\n            it.outputs.files.singleFile\n        }\n    )\n}\n"
  },
  {
    "path": "diktat-ktlint-engine/src/main/kotlin/com/pinterest/ktlint/rule/engine/api/Code.kt",
    "content": "/**\n * Copied from KtLint and open the constructor\n */\n\n@file:Suppress(\n    \"TOO_LONG_FUNCTION\",\n    \"PACKAGE_NAME_INCORRECT_PREFIX\",\n    \"PACKAGE_NAME_INCORRECT_PATH\",\n    \"KDOC_NO_CONSTRUCTOR_PROPERTY\",\n    \"MISSING_KDOC_CLASS_ELEMENTS\",\n    \"MISSING_KDOC_ON_FUNCTION\",\n    \"KDOC_WITHOUT_PARAM_TAG\",\n    \"KDOC_WITHOUT_RETURN_TAG\",\n)\n\npackage com.pinterest.ktlint.rule.engine.api\n\nimport com.pinterest.ktlint.rule.engine.api.KtLintRuleEngine.Companion.STDIN_FILE\nimport org.jetbrains.kotlin.konan.file.file\nimport java.io.File\nimport java.nio.file.Path\nimport kotlin.io.path.pathString\n\n/**\n * A representation of a block of code. Use one of the factory methods [fromFile], [fromPath], [fromSnippet] or [fromStdin] to instantiate.\n */\npublic class Code(\n    public val content: String,\n    public val fileName: String?,\n    public val filePath: Path?,\n    public val script: Boolean,\n    public val isStdIn: Boolean,\n) {\n    public fun fileNameOrStdin(): String =\n        if (isStdIn) {\n            STDIN_FILE\n        } else {\n            fileName.orEmpty()\n        }\n\n    public fun filePathOrStdin(): String =\n        if (isStdIn) {\n            STDIN_FILE\n        } else {\n            filePath?.pathString.orEmpty()\n        }\n\n    public companion object {\n        /**\n         * Create [Code] from a [file] containing valid Kotlin code or script. The '.editorconfig' files on the path to [file] are taken\n         * into account.\n         */\n        public fun fromFile(file: File): Code =\n            Code(\n                content = file.readText(),\n                fileName = file.name,\n                filePath = file.toPath(),\n                script = file.name.endsWith(\".kts\", ignoreCase = true),\n                isStdIn = false,\n            )\n\n        /**\n         * Create [Code] from a [path] to a file containing valid Kotlin code or script. The '.editorconfig' files on the path to [file] are\n         * taken into account. This method is intended to be used in unit tests. In order to work with the Ktlint test file system it needs\n         * to make additional call to get the file system which makes it slower compared to [fromFile]. Prefer to use [fromFile].\n         */\n        public fun fromPath(path: Path): Code {\n            // Resolve the file based on the file system of the original path given.\n            val file =\n                path\n                    .fileSystem\n                    .file(path.pathString)\n            return Code(\n                content = file.readStrings().joinToString(separator = \"\\n\"),\n                fileName = file.name,\n                filePath = path,\n                script = file.name.endsWith(\".kts\", ignoreCase = true),\n                isStdIn = false,\n            )\n        }\n\n        /**\n         * The [content] represent a valid piece of Kotlin code or Kotlin script. The '.editorconfig' files on the filesystem are ignored as\n         * the snippet is not associated with a file path. Use [Code.fromFile] for scanning a file while at the same time respecting the\n         * '.editorconfig' files on the path to the file.\n         */\n        public fun fromSnippet(\n            content: String,\n            script: Boolean = false,\n        ): Code =\n            Code(\n                content = content,\n                filePath = null,\n                fileName = null,\n                script = script,\n                isStdIn = true,\n            )\n\n        /**\n         * Create [Code] by reading the snippet from 'stdin'. No '.editorconfig' are taken into account.  The '.editorconfig' files on the\n         * filesystem are ignored as the snippet is not associated with a file path. Use [Code.fromFile] for scanning a file while at the\n         * same time respecting the '.editorconfig' files on the path to the file.\n         */\n        public fun fromStdin(): Code = fromSnippet(String(System.`in`.readBytes()))\n    }\n}\n"
  },
  {
    "path": "diktat-ktlint-engine/src/main/kotlin/com/saveourtool/diktat/ktlint/DiktatBaselineFactoryImpl.kt",
    "content": "package com.saveourtool.diktat.ktlint\n\nimport com.saveourtool.diktat.api.DiktatBaseline\nimport com.saveourtool.diktat.api.DiktatBaselineFactory\nimport com.saveourtool.diktat.api.DiktatProcessorListener\nimport com.saveourtool.diktat.ktlint.DiktatReporterImpl.Companion.wrap\n\nimport com.pinterest.ktlint.cli.reporter.baseline.Baseline\nimport com.pinterest.ktlint.cli.reporter.baseline.BaselineErrorHandling\nimport com.pinterest.ktlint.cli.reporter.baseline.BaselineReporterProvider\nimport com.pinterest.ktlint.cli.reporter.baseline.loadBaseline\n\nimport java.nio.file.Path\n\nimport kotlin.io.path.absolutePathString\nimport kotlin.io.path.outputStream\n\n/**\n * A factory to create or generate [DiktatBaseline] using `KtLint`\n */\nclass DiktatBaselineFactoryImpl : DiktatBaselineFactory {\n    private val baselineReporterProvider = BaselineReporterProvider()\n\n    override fun tryToLoad(\n        baselineFile: Path,\n        sourceRootDir: Path?,\n    ): DiktatBaseline? = loadBaseline(baselineFile.absolutePathString(), BaselineErrorHandling.LOG)\n        .takeIf { it.status == Baseline.Status.VALID }\n        ?.let { ktLintBaseline ->\n            DiktatBaseline { file ->\n                ktLintBaseline.lintErrorsPerFile[file.relativePathStringTo(sourceRootDir)]\n                    .orEmpty()\n                    .map { it.wrap() }\n                    .toSet()\n            }\n        }\n\n    override fun generator(\n        baselineFile: Path,\n        sourceRootDir: Path?,\n    ): DiktatProcessorListener = baselineReporterProvider.get(\n        baselineFile.outputStream(),\n        closeOutAfterAll = true,\n        emptyMap(),\n    ).wrap(sourceRootDir)\n}\n"
  },
  {
    "path": "diktat-ktlint-engine/src/main/kotlin/com/saveourtool/diktat/ktlint/DiktatProcessorFactoryImpl.kt",
    "content": "package com.saveourtool.diktat.ktlint\n\nimport com.saveourtool.diktat.DiktatProcessor\nimport com.saveourtool.diktat.DiktatProcessorFactory\nimport com.saveourtool.diktat.api.DiktatCallback\nimport com.saveourtool.diktat.api.DiktatRuleSet\nimport com.saveourtool.diktat.ktlint.KtLintRuleWrapper.Companion.toKtLint\nimport com.pinterest.ktlint.rule.engine.api.Code\nimport com.pinterest.ktlint.rule.engine.api.EditorConfigDefaults\nimport com.pinterest.ktlint.rule.engine.api.KtLintRuleEngine\nimport com.pinterest.ktlint.rule.engine.api.LintError\nimport org.ec4j.core.model.EditorConfig\nimport org.ec4j.core.model.Glob\nimport org.ec4j.core.model.Property\nimport org.ec4j.core.model.PropertyType\nimport java.nio.file.Path\nimport kotlin.io.path.name\n\nprivate typealias LintCallback = (LintError) -> Unit\n\n/**\n * A factory to create [DiktatProcessor] using [DiktatProcessorFactory] and `KtLint` as engine\n */\nclass DiktatProcessorFactoryImpl : DiktatProcessorFactory {\n    override fun invoke(diktatRuleSet: DiktatRuleSet): DiktatProcessor {\n        val ktLintRuleEngine = diktatRuleSet.toKtLintEngine()\n        return object : DiktatProcessor {\n            override fun fix(\n                file: Path,\n                callback: DiktatCallback,\n            ): String = ktLintRuleEngine.formatSilentlyThenLint(file.toKtLint(), callback.toKtLintForLint())\n            override fun fix(\n                code: String,\n                virtualPath: Path?,\n                callback: DiktatCallback\n            ): String = ktLintRuleEngine.formatSilentlyThenLint(code.toKtLint(virtualPath), callback.toKtLintForLint())\n            override fun check(\n                file: Path,\n                callback: DiktatCallback,\n            ) = ktLintRuleEngine.lint(file.toKtLint(), callback.toKtLintForLint())\n            override fun check(\n                code: String,\n                virtualPath: Path?,\n                callback: DiktatCallback\n            ) = ktLintRuleEngine.lint(code.toKtLint(virtualPath), callback.toKtLintForLint())\n        }\n    }\n\n    companion object {\n        private fun DiktatRuleSet.toKtLintEngine(): KtLintRuleEngine = KtLintRuleEngine(\n            ruleProviders = toKtLint(),\n            // use platform dependent endlines in process of editing\n            editorConfigDefaults = EditorConfigDefaults(\n                EditorConfig.builder()\n                    .openSection()\n                    .glob(Glob(\"**\"))\n                    .property(\n                        Property.builder()\n                            .name(PropertyType.end_of_line.name)\n                            .type(PropertyType.end_of_line)\n                            .value(PropertyType.EndOfLineValue.ofEndOfLineString(System.lineSeparator())?.name)\n                    )\n                    .closeSection()\n                    .build()\n            )\n        )\n\n        private fun Path.toKtLint(): Code = Code.fromFile(this.toFile())\n\n        private fun String.toKtLint(virtualPath: Path?): Code = Code(\n            content = this,\n            fileName = virtualPath?.name,\n            filePath = virtualPath,\n            script = virtualPath?.name?.endsWith(\".kts\", ignoreCase = true) ?: false,\n            isStdIn = virtualPath == null,\n        )\n\n        private fun DiktatCallback.toKtLintForLint(): LintCallback = { error ->\n            this(error.wrap(), false)\n        }\n\n        private fun KtLintRuleEngine.formatSilentlyThenLint(\n            code: Code,\n            callback: LintCallback,\n        ): String {\n            // this API method is significantly changed in Ktlint, so -werror was disabled due to it\n            @Suppress(\"Deprecation\")\n            val formatResult = format(code)\n            lint(\n                code = Code(\n                    content = formatResult,\n                    fileName = code.fileName,\n                    filePath = code.filePath,\n                    script = code.script,\n                    isStdIn = code.isStdIn,\n                ),\n                callback = callback,\n            )\n            return formatResult\n        }\n    }\n}\n"
  },
  {
    "path": "diktat-ktlint-engine/src/main/kotlin/com/saveourtool/diktat/ktlint/DiktatReporterFactoryImpl.kt",
    "content": "package com.saveourtool.diktat.ktlint\n\nimport com.saveourtool.diktat.api.DiktatReporter\nimport com.saveourtool.diktat.api.DiktatReporterCreationArguments\nimport com.saveourtool.diktat.api.DiktatReporterFactory\nimport com.saveourtool.diktat.api.DiktatReporterType\nimport com.saveourtool.diktat.api.PlainDiktatReporterCreationArguments\nimport com.saveourtool.diktat.ktlint.DiktatReporterImpl.Companion.wrap\nimport com.pinterest.ktlint.cli.reporter.checkstyle.CheckStyleReporterProvider\nimport com.pinterest.ktlint.cli.reporter.html.HtmlReporterProvider\nimport com.pinterest.ktlint.cli.reporter.json.JsonReporterProvider\nimport com.pinterest.ktlint.cli.reporter.plain.Color\nimport com.pinterest.ktlint.cli.reporter.plain.PlainReporterProvider\nimport com.pinterest.ktlint.cli.reporter.sarif.SarifReporterProvider\nimport kotlin.io.path.pathString\n\n/**\n * A factory to create [DiktatReporter] using `KtLint`\n */\nclass DiktatReporterFactoryImpl : DiktatReporterFactory {\n    private val plainReporterProvider = PlainReporterProvider()\n\n    /**\n     * All reporters which __KtLint__ provides\n     */\n    private val reporterProviders = mapOf(\n        DiktatReporterType.JSON to JsonReporterProvider(),\n        DiktatReporterType.SARIF to SarifReporterProvider(),\n        DiktatReporterType.CHECKSTYLE to CheckStyleReporterProvider(),\n        DiktatReporterType.HTML to HtmlReporterProvider(),\n        DiktatReporterType.PLAIN to plainReporterProvider,\n    )\n\n    override val colorNamesInPlain: Set<String>\n        get() = Color.entries.map { it.name }.toSet()\n\n    override fun invoke(\n        args: DiktatReporterCreationArguments,\n    ): DiktatReporter {\n        val opts = when {\n            args is PlainDiktatReporterCreationArguments -> buildMap<String, Any> {\n                put(\"color\", args.colorName?.let { true } ?: false)\n                put(\"color_name\", args.colorName ?: Color.DARK_GRAY)\n                args.groupByFile?.let { put(\"group_by_file\", it) }\n            }.mapValues { it.value.toString() }\n            args.reporterType == DiktatReporterType.PLAIN -> mapOf(\n                \"color_name\" to Color.DARK_GRAY.name,\n                \"group_by_file\" to false.toString(),\n            )\n            args.reporterType == DiktatReporterType.PLAIN_GROUP_BY_FILE -> mapOf(\n                \"color_name\" to Color.DARK_GRAY.name,\n                \"group_by_file\" to true.toString(),\n            )\n            else -> emptyMap()\n        }\n\n        val reporterProvider = reporterProviders[args.reporterType] ?: throw IllegalArgumentException(\"Not supported reporter id by ${DiktatBaselineFactoryImpl::class.simpleName}\")\n        if (reporterProvider is SarifReporterProvider) {\n            args.sourceRootDir?.let { System.setProperty(\"user.home\", it.pathString) }\n        }\n        return reporterProvider.get(args.outputStream, args.closeOutputStreamAfterAll, opts).wrap(args.sourceRootDir)\n    }\n}\n"
  },
  {
    "path": "diktat-ktlint-engine/src/main/kotlin/com/saveourtool/diktat/ktlint/DiktatReporterImpl.kt",
    "content": "package com.saveourtool.diktat.ktlint\n\nimport com.saveourtool.diktat.api.DiktatError\nimport com.saveourtool.diktat.api.DiktatReporter\nimport com.saveourtool.diktat.ktlint.ReporterV2Wrapper.Companion.unwrapIfNeeded\nimport com.saveourtool.diktat.util.DiktatProcessorListenerWrapper\nimport com.pinterest.ktlint.cli.reporter.core.api.ReporterV2\nimport java.nio.file.Path\n\n/**\n * [DiktatReporter] using __KtLint__\n *\n * @param ktLintReporter\n * @param sourceRootDir\n */\nclass DiktatReporterImpl(\n    ktLintReporter: ReporterV2,\n    private val sourceRootDir: Path?,\n) : DiktatProcessorListenerWrapper<ReporterV2>(ktLintReporter) {\n    override fun doBeforeAll(wrappedValue: ReporterV2, files: Collection<Path>): Unit = wrappedValue.beforeAll()\n    override fun doBefore(wrappedValue: ReporterV2, file: Path): Unit = wrappedValue.before(file.relativePathStringTo(sourceRootDir))\n    override fun doOnError(\n        wrappedValue: ReporterV2,\n        file: Path,\n        error: DiktatError,\n        isCorrected: Boolean,\n    ): Unit = wrappedValue.onLintError(file.relativePathStringTo(sourceRootDir), error.toKtLintForCli())\n    override fun doAfter(wrappedValue: ReporterV2, file: Path): Unit = wrappedValue.after(file.relativePathStringTo(sourceRootDir))\n    override fun doAfterAll(wrappedValue: ReporterV2): Unit = wrappedValue.afterAll()\n\n    companion object {\n        /**\n         * @param sourceRootDir\n         * @return [DiktatReporter] which wraps __KtLint__'s [ReporterV2]\n         */\n        fun ReporterV2.wrap(sourceRootDir: Path?): DiktatReporter = DiktatReporterImpl(this, sourceRootDir)\n\n        /**\n         * @return __KtLint__'s [ReporterV2]\n         */\n        fun DiktatReporter.unwrapToKtlint(): ReporterV2 = unwrap<ReporterV2>().unwrapIfNeeded()\n    }\n}\n"
  },
  {
    "path": "diktat-ktlint-engine/src/main/kotlin/com/saveourtool/diktat/ktlint/KtLintRuleWrapper.kt",
    "content": "package com.saveourtool.diktat.ktlint\n\nimport com.saveourtool.diktat.api.DiktatRule\nimport com.saveourtool.diktat.api.DiktatRuleSet\nimport com.saveourtool.diktat.common.config.rules.DIKTAT_RULE_SET_ID\nimport com.pinterest.ktlint.rule.engine.core.api.Rule\nimport com.pinterest.ktlint.rule.engine.core.api.Rule.VisitorModifier.RunAfterRule.Mode\nimport com.pinterest.ktlint.rule.engine.core.api.RuleId\nimport com.pinterest.ktlint.rule.engine.core.api.RuleProvider\nimport org.jetbrains.kotlin.com.intellij.lang.ASTNode\n\nprivate typealias EmitType = (offset: Int, errorMessage: String, canBeAutoCorrected: Boolean) -> Unit\n\n/**\n * This is a wrapper around __KtLint__'s [Rule] which adjusts visitorModifiers to keep order with prevRule.\n * @property rule\n */\nclass KtLintRuleWrapper(\n    val rule: DiktatRule,\n    prevRuleId: RuleId? = null,\n) : Rule(\n    ruleId = rule.id.toRuleId(DIKTAT_RULE_SET_ID),\n    about = about,\n    visitorModifiers = createVisitorModifiers(rule, prevRuleId),\n) {\n    @Deprecated(\"Marked for removal in Ktlint 2.0. Please implement interface RuleAutocorrectApproveHandler.\")\n    override fun beforeVisitChildNodes(\n        node: ASTNode,\n        autoCorrect: Boolean,\n        emit: EmitType,\n    ) = rule.invoke(node, autoCorrect) { offset, errorMessage, canBeAutoCorrected ->\n        emit.invoke(offset, errorMessage.correctErrorDetail(canBeAutoCorrected), canBeAutoCorrected)\n    }\n\n    companion object {\n        private val about: About = About(\n            maintainer = \"Diktat\",\n            repositoryUrl = \"https://github.com/saveourtool/diktat\",\n            issueTrackerUrl = \"https://github.com/saveourtool/diktat/issues\",\n        )\n\n        private fun Sequence<DiktatRule>.wrapRulesToProviders(): Sequence<RuleProvider> = runningFold(null as RuleProvider?) { prevRuleProvider, diktatRule ->\n            val prevRuleId = prevRuleProvider?.ruleId?.value?.toRuleId(DIKTAT_RULE_SET_ID)\n            RuleProvider(\n                provider = { KtLintRuleWrapper(diktatRule, prevRuleId) },\n            )\n        }.filterNotNull()\n\n        /**\n         * @return [Set] of __KtLint__'s [RuleProvider]s created from [DiktatRuleSet]\n         */\n        fun DiktatRuleSet.toKtLint(): Set<RuleProvider> = rules\n            .asSequence()\n            .wrapRulesToProviders()\n            .toSet()\n\n        private fun createVisitorModifiers(\n            rule: DiktatRule,\n            prevRuleId: RuleId?,\n        ): Set<VisitorModifier> = prevRuleId?.run {\n            val ruleId = rule.id.toRuleId(DIKTAT_RULE_SET_ID)\n            require(ruleId != prevRuleId) {\n                \"PrevRule has same ID as rule: $ruleId\"\n            }\n            setOf(\n                VisitorModifier.RunAfterRule(\n                    ruleId = prevRuleId,\n                    mode = Mode.REGARDLESS_WHETHER_RUN_AFTER_RULE_IS_LOADED_OR_DISABLED\n                )\n            )\n        } ?: emptySet()\n\n        /**\n         * @return a rule to which a logic is delegated\n         */\n        internal fun Rule.unwrap(): DiktatRule = (this as? KtLintRuleWrapper)?.rule ?: error(\"Provided rule ${javaClass.simpleName} is not wrapped by diktat\")\n    }\n}\n"
  },
  {
    "path": "diktat-ktlint-engine/src/main/kotlin/com/saveourtool/diktat/ktlint/KtLintUtils.kt",
    "content": "/**\n * This file contains util methods for __KtLint__\n */\n\npackage com.saveourtool.diktat.ktlint\n\nimport com.saveourtool.diktat.api.DiktatCallback\nimport com.saveourtool.diktat.api.DiktatError\nimport com.saveourtool.diktat.api.DiktatRuleSet\nimport com.saveourtool.diktat.common.config.rules.DIKTAT_RULE_SET_ID\n\nimport com.pinterest.ktlint.cli.reporter.core.api.KtlintCliError\nimport com.pinterest.ktlint.cli.reporter.core.api.ReporterProviderV2\nimport com.pinterest.ktlint.cli.reporter.core.api.ReporterV2\nimport com.pinterest.ktlint.rule.engine.api.LintError\nimport com.pinterest.ktlint.rule.engine.core.api.RuleId\nimport org.intellij.lang.annotations.Language\nimport org.jetbrains.kotlin.utils.addToStdlib.applyIf\nimport java.io.OutputStream\nimport java.io.PrintStream\n\nimport java.nio.file.Path\n\nimport kotlin.io.path.invariantSeparatorsPathString\nimport kotlin.io.path.relativeToOrSelf\n\nprivate const val CANNOT_BE_AUTOCORRECTED_SUFFIX = \" (cannot be auto-corrected)\"\n\n/**\n * Makes sure this _rule id_ is qualified with a _rule set id_.\n *\n * @param ruleSetId the _rule set id_; defaults to [DIKTAT_RULE_SET_ID].\n * @return the fully-qualified _rule id_ in the form of `ruleSetId:ruleId` as __KtLint__'s [RuleId].\n * @see DIKTAT_RULE_SET_ID\n * @since 1.2.4\n */\nfun String.toRuleId(ruleSetId: String = DIKTAT_RULE_SET_ID): RuleId =\n    when {\n        this.contains(':') -> RuleId(this)\n        else -> RuleId(\"$ruleSetId:$this\")\n    }\n\n/**\n * @return [DiktatError] from KtLint's [LintError]\n */\nfun LintError.wrap(): DiktatError = DiktatError(\n    line = this@wrap.line,\n    col = this@wrap.col,\n    ruleId = this@wrap.ruleId.value,\n    detail = this@wrap.detail.removeSuffix(CANNOT_BE_AUTOCORRECTED_SUFFIX),\n    canBeAutoCorrected = this@wrap.canBeAutoCorrected,\n)\n\n/**\n * @return [DiktatError] from KtLint's [KtlintCliError]\n */\nfun KtlintCliError.wrap(): DiktatError = DiktatError(\n    line = this@wrap.line,\n    col = this@wrap.col,\n    ruleId = this@wrap.ruleId,\n    detail = this@wrap.detail.removeSuffix(CANNOT_BE_AUTOCORRECTED_SUFFIX),\n    canBeAutoCorrected = this@wrap.status == KtlintCliError.Status.LINT_CAN_BE_AUTOCORRECTED,\n)\n\n/**\n * @return KtLint [LintError] from [DiktatError] or exception\n */\nfun DiktatError.toKtLintForCli(): KtlintCliError = KtlintCliError(\n    line = this@toKtLintForCli.line,\n    col = this@toKtLintForCli.col,\n    ruleId = this@toKtLintForCli.ruleId,\n    detail = this@toKtLintForCli.detail.correctErrorDetail(this@toKtLintForCli.canBeAutoCorrected),\n    status = if (this@toKtLintForCli.canBeAutoCorrected) {\n        KtlintCliError.Status.LINT_CAN_BE_AUTOCORRECTED\n    } else {\n        KtlintCliError.Status.LINT_CAN_NOT_BE_AUTOCORRECTED\n    }\n)\n\n/**\n * @receiver [DiktatError.detail]\n * @param canBeAutoCorrected [DiktatError.canBeAutoCorrected]\n * @return input string with [CANNOT_BE_AUTOCORRECTED_SUFFIX] if it's required\n */\nfun String.correctErrorDetail(canBeAutoCorrected: Boolean): String = if (canBeAutoCorrected) {\n    this\n} else {\n    \"$this$CANNOT_BE_AUTOCORRECTED_SUFFIX\"\n}\n\n/**\n * @param sourceRootDir\n * @return relative path to [sourceRootDir] as [String]\n */\nfun Path.relativePathStringTo(sourceRootDir: Path?): String = (sourceRootDir?.let { relativeToOrSelf(it) } ?: this).invariantSeparatorsPathString\n\n/**\n * @param out [OutputStream] for [ReporterV2]\n * @param closeOutAfterAll close [OutputStream] in [ReporterV2.afterAll]\n * @param opt configuration for [ReporterV2]\n * @return created [ReporterV2] which closes [out] in [ReporterV2.afterAll] if it's required\n */\nfun <R : ReporterV2> ReporterProviderV2<R>.get(\n    out: OutputStream,\n    closeOutAfterAll: Boolean,\n    opt: Map<String, String>,\n): ReporterV2 = get(out.printStream(), opt).applyIf(closeOutAfterAll) {\n    closeAfterAll(out)\n}\n\n/**\n * Enables ignoring autocorrected errors when in \"fix\" mode (i.e. when\n * [com.pinterest.ktlint.core.KtLint.format] is invoked).\n *\n * Before version 0.47, _Ktlint_ only reported non-corrected errors in \"fix\"\n * mode.\n * Now, this has changed.\n *\n * @receiver the instance of _Ktlint_ parameters.\n * @return the instance [DiktatCallback] that ignores corrected errors.\n * @see com.pinterest.ktlint.core.KtLint.format\n * @since 1.2.4\n */\nprivate fun DiktatCallback.ignoreCorrectedErrors(): DiktatCallback = DiktatCallback { error, isCorrected ->\n    if (!isCorrected) {\n        this@ignoreCorrectedErrors(error, false)\n    }\n}\n\nprivate fun OutputStream.printStream(): PrintStream = (this as? PrintStream) ?: PrintStream(this)\n\nprivate fun ReporterV2.closeAfterAll(outputStream: OutputStream): ReporterV2 = object : ReporterV2Wrapper(this@closeAfterAll) {\n    override fun afterAll() {\n        super.afterAll()\n        outputStream.flush()\n        outputStream.close()\n    }\n}\n\n/**\n * @param ruleSetSupplier\n * @param file\n * @param cb callback to be called on unhandled [LintError]s\n * @return formatted code\n */\n@Suppress(\"LAMBDA_IS_NOT_LAST_PARAMETER\")\nfun format(\n    ruleSetSupplier: () -> DiktatRuleSet,\n    file: Path,\n    cb: DiktatCallback,\n): String = DiktatProcessorFactoryImpl().invoke(ruleSetSupplier())\n    .fix(\n        file = file,\n        callback = cb.ignoreCorrectedErrors(),\n    )\n\n/**\n * @param ruleSetSupplier\n * @param file\n * @param cb callback to be called on unhandled [LintError]s\n * @return [Unit]\n */\n@Suppress(\"LAMBDA_IS_NOT_LAST_PARAMETER\")\nfun check(\n    ruleSetSupplier: () -> DiktatRuleSet,\n    file: Path,\n    cb: DiktatCallback = DiktatCallback.empty\n) = DiktatProcessorFactoryImpl().invoke(ruleSetSupplier())\n    .check(\n        file = file,\n        callback = cb.ignoreCorrectedErrors(),\n    )\n\n/**\n * @param ruleSetSupplier\n * @param text\n * @param cb callback to be called on unhandled [LintError]s\n * @return [Unit]\n */\n@Suppress(\"LAMBDA_IS_NOT_LAST_PARAMETER\")\nfun check(\n    ruleSetSupplier: () -> DiktatRuleSet,\n    @Language(\"kotlin\") text: String,\n    cb: DiktatCallback = DiktatCallback.empty\n) = DiktatProcessorFactoryImpl().invoke(ruleSetSupplier())\n    .check(\n        code = text,\n        virtualPath = null,\n        callback = cb.ignoreCorrectedErrors(),\n    )\n"
  },
  {
    "path": "diktat-ktlint-engine/src/main/kotlin/com/saveourtool/diktat/ktlint/ReporterV2Wrapper.kt",
    "content": "package com.saveourtool.diktat.ktlint\n\nimport com.pinterest.ktlint.cli.reporter.core.api.KtlintCliError\nimport com.pinterest.ktlint.cli.reporter.core.api.ReporterV2\n\n/**\n * Wrapper for [ReporterV2]\n *\n * @param reporterV2\n */\nopen class ReporterV2Wrapper(private val reporterV2: ReporterV2) : ReporterV2 {\n    override fun beforeAll() = reporterV2.beforeAll()\n\n    override fun before(file: String) = reporterV2.before(file)\n\n    override fun onLintError(file: String, ktlintCliError: KtlintCliError) = reporterV2.onLintError(file, ktlintCliError)\n\n    override fun after(file: String) = reporterV2.after(file)\n\n    override fun afterAll() = reporterV2.afterAll()\n\n    companion object {\n        /**\n         * @return unwrapped [ReporterV2Wrapper] if it's required\n         */\n        fun ReporterV2.unwrapIfNeeded(): ReporterV2 = if (this is ReporterV2Wrapper) {\n            this.reporterV2\n        } else {\n            this\n        }\n    }\n}\n"
  },
  {
    "path": "diktat-ktlint-engine/src/test/kotlin/com/saveourtool/diktat/ktlint/KtLintRuleWrapperTest.kt",
    "content": "package com.saveourtool.diktat.ktlint\n\nimport com.saveourtool.diktat.api.DiktatErrorEmitter\nimport com.saveourtool.diktat.api.DiktatRule\nimport com.saveourtool.diktat.api.DiktatRuleSet\nimport com.saveourtool.diktat.ktlint.KtLintRuleWrapper.Companion.toKtLint\nimport com.saveourtool.diktat.ktlint.KtLintRuleWrapper.Companion.unwrap\nimport com.pinterest.ktlint.rule.engine.api.Code\nimport com.pinterest.ktlint.rule.engine.api.KtLintRuleEngine\nimport com.pinterest.ktlint.rule.engine.core.api.Rule\nimport com.pinterest.ktlint.rule.engine.core.api.RuleProvider\nimport org.assertj.core.api.Assertions.assertThat\nimport org.intellij.lang.annotations.Language\nimport org.jetbrains.kotlin.com.intellij.lang.ASTNode\nimport org.junit.jupiter.api.Assertions\nimport org.junit.jupiter.api.Test\n\nclass KtLintRuleWrapperTest {\n    @Test\n    fun `check KtLintRuleSetWrapper with duplicate`() {\n        val rule = mockRule(\"rule\")\n        Assertions.assertThrows(IllegalArgumentException::class.java) {\n            DiktatRuleSet(listOf(rule, rule)).toKtLint()\n        }\n    }\n\n    @Test\n    fun `check OrderedRule`() {\n        val rule1 = mockRule(id = \"rule-first\")\n        val rule2 = mockRule(id = \"rule-second\")\n\n        val orderedRuleProviders = DiktatRuleSet(listOf(rule1, rule2)).toKtLint()\n\n        val orderedRuleProviderIterator = orderedRuleProviders.iterator()\n        val orderedRule1 = orderedRuleProviderIterator.next().createNewRuleInstance()\n        val orderedRule2 = orderedRuleProviderIterator.next().createNewRuleInstance()\n        Assertions.assertFalse(orderedRuleProviderIterator.hasNext(), \"Extra elements after ordering\")\n\n        Assertions.assertEquals(rule1, orderedRule1.unwrap(), \"First rule is modified\")\n\n        orderedRule2.visitorModifiers\n            .filterIsInstance<Rule.VisitorModifier.RunAfterRule>()\n            .also {\n                Assertions.assertEquals(1, it.size,\n                    \"Found invalid count of Rule.VisitorModifier.RunAfterRule\")\n            }\n            .first()\n            .let {\n                Assertions.assertEquals(rule1.id.toRuleId(), it.ruleId,\n                    \"Invalid ruleId in Rule.VisitorModifier.RunAfterRule\")\n            }\n    }\n\n    @Test\n    @Suppress(\"TOO_LONG_FUNCTION\")\n    fun `KtLint keeps order with RuleVisitorModifierRunAfterRule`() {\n        val actualRuleInvocationOrder: MutableList<String> = mutableListOf()\n        val onVisit: (DiktatRule) -> Unit = { rule ->\n            actualRuleInvocationOrder += rule.id\n        }\n        val rules: List<DiktatRule> = sequenceOf(\"ccc\", \"bbb\", \"aaa\").map { ruleId ->\n            mockRule(\n                id = ruleId,\n                onVisit = onVisit\n            )\n        }.toList()\n        assertThat(rules).isNotEmpty\n\n        /*\n         * Make sure the rules are not sorted by id.\n         */\n        val rulesOrderedById: List<DiktatRule> = rules.sortedBy(DiktatRule::id)\n        assertThat(rules).containsExactlyInAnyOrder(*rulesOrderedById.toTypedArray())\n        assertThat(rules).isNotEqualTo(rulesOrderedById)\n\n        /*\n         * Make sure OrderedRuleSet preserves the order.\n         */\n        val ruleProviders = DiktatRuleSet(rules).toKtLint()\n        assertThat(ruleProviders.map(RuleProvider::createNewRuleInstance).map(Rule::ruleId))\n            .containsExactlyElementsOf(rules.map(DiktatRule::id).map { it.toRuleId() })\n\n        @Language(\"kotlin\")\n        val code = \"fun foo() { }\"\n\n        KtLintRuleEngine(\n            ruleProviders = ruleProviders\n        ).lint(\n            code = Code.fromSnippet(\n                content = code\n            )\n        )\n\n        val ruleCount = rules.size\n        assertThat(actualRuleInvocationOrder)\n            .describedAs(\"The ordered list of rule invocations\")\n            .matches({ order ->\n                order.size % ruleCount == 0\n            }, \"has a size which is multiple of $ruleCount\")\n\n        /*\n         * This is the count of AST nodes in `code` above.\n         */\n        val astNodeCount = actualRuleInvocationOrder.size / ruleCount\n\n        /*-\n         * This is new in ktlint 0.47.\n         * Previously, rules were applied in this sequence:\n         *\n         * A -> B -> C (File)\n         *      |\n         *      V\n         * A -> B -> C (Node)\n         *      |\n         *      V\n         * A -> B -> C (Leaf)\n         *\n         * Now, each rule is recursively applied to all AST nodes, and then the\n         * control is passed to the next rule:\n         *\n         * A(File) -> A(Node) -> A(Leaf)\n         *            |\n         *            V\n         * B(File) -> B(Node) -> B(Leaf)\n         *            |\n         *            V\n         * C(File) -> C(Node) -> C(Leaf)\n         */\n         val expectedRuleInvocationOrder = rules.asSequence()\n              .map(DiktatRule::id)\n              .flatMap { ruleId ->\n                  generateSequence { ruleId }.take(astNodeCount)\n              }\n              .toList()\n\n        assertThat(actualRuleInvocationOrder)\n            .containsExactlyElementsOf(expectedRuleInvocationOrder)\n    }\n\n    companion object {\n        private fun mockRule(\n            id: String,\n            onVisit: (DiktatRule) -> Unit = { }\n        ): DiktatRule = object : DiktatRule {\n            override val id: String\n                get() = id\n            override fun invoke(node: ASTNode, autoCorrect: Boolean, emitter: DiktatErrorEmitter) {\n                onVisit(this)\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "diktat-maven-plugin/README.md",
    "content": "## Local testing\n\nYou can build and publish to maven local by using `:diktat-api:publishToMavenLocal :diktat-rules:publishToMavenLocal :diktat-runner:publishToMavenLocal :diktat-common:publishToMavenLocal :diktat-ktlint-engine:publishToMavenLocal :diktat-maven-plugin:publishToMavenLocal`.\nThen you can use a built version in projects in examples.\nA calculated version will be printed in logs by `reckon` plugin.\n"
  },
  {
    "path": "diktat-maven-plugin/build.gradle.kts",
    "content": "import com.saveourtool.diktat.buildutils.configurePublications\nimport de.benediktritter.maven.plugin.development.task.GenerateHelpMojoSourcesTask\nimport de.benediktritter.maven.plugin.development.task.GenerateMavenPluginDescriptorTask\n\nplugins {\n    id(\"com.saveourtool.diktat.buildutils.kotlin-jvm-configuration\")\n    id(\"com.saveourtool.diktat.buildutils.code-quality-convention\")\n    id(\"com.saveourtool.diktat.buildutils.publishing-configuration\")\n    id(\"de.benediktritter.maven-plugin-development\") version \"0.4.3\"\n    `maven-publish`\n}\n\ndependencies {\n    compileOnly(libs.maven.plugin.annotations)\n    compileOnly(libs.maven.core)\n\n    implementation(libs.kotlin.stdlib.jdk8)\n    implementation(projects.diktatRunner)\n\n    testImplementation(libs.junit.jupiter.api)\n    testImplementation(libs.junit.vintage.engine)\n    testImplementation(libs.junit.jupiter.extension.itf)\n    testImplementation(libs.maven.plugin.testing.harness)\n    // to use org.apache.maven.repository.RepositorySystem in newer maven versions and maybe other classes\n    testImplementation(libs.maven.compat)\n    testImplementation(libs.assertj.core)\n    testImplementation(libs.plexus.cipher)\n}\n\ntasks.withType<GenerateMavenPluginDescriptorTask> {\n    notCompatibleWithConfigurationCache(\"https://github.com/britter/maven-plugin-development/issues/8\")\n}\n\ntasks.withType<GenerateHelpMojoSourcesTask> {\n    notCompatibleWithConfigurationCache(\"https://github.com/britter/maven-plugin-development/issues/8\")\n}\n\nmavenPlugin {\n    goalPrefix.set(\"diktat\")\n}\n\npublishing {\n    publications {\n        create<MavenPublication>(\"mavenPlugin\") {\n            from(components[\"java\"])\n        }\n    }\n}\nconfigurePublications()\n"
  },
  {
    "path": "diktat-maven-plugin/src/main/kotlin/com/saveourtool/diktat/plugin/maven/DiktatBaseMojo.kt",
    "content": "package com.saveourtool.diktat.plugin.maven\n\nimport com.saveourtool.diktat.DiktatRunner\nimport com.saveourtool.diktat.DiktatRunnerArguments\nimport com.saveourtool.diktat.diktatRunnerFactory\nimport com.saveourtool.diktat.plugin.maven.reporters.GitHubActionsReporter\nimport com.saveourtool.diktat.plugin.maven.reporters.PlainReporter\nimport com.saveourtool.diktat.plugin.maven.reporters.Reporter\nimport com.saveourtool.diktat.plugin.maven.reporters.Reporters\nimport com.saveourtool.diktat.util.isKotlinCodeOrScript\n\nimport org.apache.maven.plugin.AbstractMojo\nimport org.apache.maven.plugin.Mojo\nimport org.apache.maven.plugin.MojoExecutionException\nimport org.apache.maven.plugin.MojoFailureException\nimport org.apache.maven.plugins.annotations.Parameter\nimport org.apache.maven.project.MavenProject\n\nimport java.io.File\nimport java.nio.file.Path\nimport java.nio.file.Paths\nimport kotlin.io.path.inputStream\nimport kotlin.io.path.isRegularFile\n\n/**\n * Base [Mojo] for checking and fixing code using diktat\n */\nabstract class DiktatBaseMojo : AbstractMojo() {\n    /**\n     * Property that will be used if you need to publish the report to GitHub\n     */\n    @Parameter(property = \"diktat.githubActions\")\n    var githubActions = false\n\n    /**\n     * The reporters to use\n     */\n    @Parameter\n    var reporters: Reporters? = null\n\n    /**\n     * Baseline file, containing a list of errors that will be ignored.\n     * If this file doesn't exist, it will be created on the first invocation.\n     * Default: no baseline.\n     */\n    @Parameter(property = \"diktat.baseline\")\n    var baseline: File? = null\n\n    /**\n     * Path to diktat yml config file. Can be either absolute or relative to project's root directory.\n     */\n    @Parameter(property = \"diktat.config\", defaultValue = \"diktat-analysis.yml\")\n    lateinit var diktatConfigFile: String\n\n    /**\n     * Property that can be used to access various maven settings\n     */\n    @Parameter(defaultValue = \"\\${project}\", readonly = true)\n    private lateinit var mavenProject: MavenProject\n\n    /**\n     * Paths that will be scanned for .kt(s) files\n     */\n    @Parameter(property = \"diktat.inputs\", defaultValue = \"\\${project.basedir}/src\")\n    lateinit var inputs: List<String>\n\n    /**\n     * Paths that will be excluded if encountered during diktat run\n     */\n    @Parameter(property = \"diktat.excludes\", defaultValue = \"\")\n    lateinit var excludes: List<String>\n\n    /**\n     * @param runner instance of [DiktatRunner] used in analysis\n     * @param args arguments for [DiktatRunner]\n     * @return count of errors\n     */\n    abstract fun runAction(\n        runner: DiktatRunner,\n        args: DiktatRunnerArguments,\n    ): Int\n\n    /**\n     * Perform code check using diktat ruleset\n     *\n     * @throws MojoFailureException if code style check was not passed\n     * @throws MojoExecutionException if an exception in __KtLint__ has been thrown\n     */\n    override fun execute() {\n        val configFile = resolveConfig()\n        log.info(\"Running diKTat plugin with ${configFile?.let { \"configuration file $it\" } ?: \"default configuration\" } and inputs $inputs\" +\n                if (excludes.isNotEmpty()) \" and excluding $excludes\" else \"\"\n        )\n\n        val sourceRootDir = getSourceRootDirTransitive()\n        val reporters: List<Reporter> = (reporters?.getAll() ?: listOf(PlainReporter()))\n            .let { all ->\n                if (githubActions && all.filterIsInstance<GitHubActionsReporter>().isEmpty()) {\n                    all + GitHubActionsReporter()\n                } else {\n                    all\n                }\n            }\n\n        val reporterArgsList = reporters.map { it.toCreationArguments(mavenProject, sourceRootDir) }\n        val args = DiktatRunnerArguments(\n            configInputStream = configFile?.inputStream(),\n            sourceRootDir = sourceRootDir,\n            files = files(),\n            baselineFile = baseline?.toPath(),\n            reporterArgsList = reporterArgsList,\n        )\n        val diktatRunner = diktatRunnerFactory(args)\n        val errorCounter = runAction(\n            runner = diktatRunner,\n            args = args,\n        )\n        if (errorCounter > 0) {\n            throw MojoFailureException(\"There are $errorCounter lint errors\")\n        }\n    }\n\n    /**\n     * Function that searches diktat config file in maven project hierarchy.\n     * If [diktatConfigFile] is absolute, it's path is used. If [diktatConfigFile] is relative, this method looks for it in all maven parent projects.\n     * This way config file can be placed in parent module directory and used in all child modules too.\n     *\n     * @return a configuration file. File by this path exists.\n     */\n    private fun resolveConfig(): Path? {\n        val file = Paths.get(diktatConfigFile)\n        if (file.isAbsolute) {\n            return file\n        }\n\n        return generateSequence(mavenProject) { it.parent }\n            .map { it.basedir.toPath().resolve(diktatConfigFile) }\n            .firstOrNull { it.isRegularFile() }\n    }\n\n    private fun getSourceRootDirTransitive(): Path = generateSequence(mavenProject) { project ->\n        val parent = project.parent\n        parent?.basedir?.let {\n            parent\n        }\n    }.last().basedir.toPath()\n\n    private fun files(): List<Path> {\n        val (excludedDirs, excludedFiles) = excludes.map(::File).partition { it.isDirectory }\n        return inputs\n            .asSequence()\n            .map(::File)\n            .flatMap {\n                it.files(excludedDirs, excludedFiles)\n            }\n            .map { it.toPath() }\n            .toList()\n    }\n\n    @Suppress(\"TYPE_ALIAS\")\n    private fun File.files(\n        excludedDirs: List<File>,\n        excludedFiles: List<File>,\n    ): Sequence<File> = walk()\n        .filter { file ->\n            file.isFile && file.toPath().isKotlinCodeOrScript()\n        }\n        .filterNot { file ->\n            file in excludedFiles || excludedDirs.any { file.startsWith(it) }\n        }\n}\n"
  },
  {
    "path": "diktat-maven-plugin/src/main/kotlin/com/saveourtool/diktat/plugin/maven/DiktatMojo.kt",
    "content": "/**\n * MOJOs for goals of diktat plugin\n */\n\npackage com.saveourtool.diktat.plugin.maven\n\nimport com.saveourtool.diktat.DiktatRunner\nimport com.saveourtool.diktat.DiktatRunnerArguments\n\nimport org.apache.maven.plugins.annotations.Mojo\n\n/**\n * Main [Mojo] that call diktat's rules on [inputs] files\n */\n@Mojo(name = \"check\")\n@Suppress(\"unused\")\nclass DiktatCheckMojo : DiktatBaseMojo() {\n    override fun runAction(\n        runner: DiktatRunner,\n        args: DiktatRunnerArguments,\n    ): Int = runner.checkAll(args)\n}\n\n/**\n * Main [Mojo] that call diktat's rules on [inputs] files\n * and fixes discovered errors\n */\n@Mojo(name = \"fix\")\n@Suppress(\"unused\")\nclass DiktatFixMojo : DiktatBaseMojo() {\n    override fun runAction(\n        runner: DiktatRunner,\n        args: DiktatRunnerArguments,\n    ): Int = runner.fixAll(args) { updatedFile ->\n        log.info(\"Original and formatted content differ, writing to ${updatedFile.fileName}...\")\n    }\n}\n"
  },
  {
    "path": "diktat-maven-plugin/src/main/kotlin/com/saveourtool/diktat/plugin/maven/Utils.kt",
    "content": "/**\n * Utilities for diktat maven plugin\n */\n\npackage com.saveourtool.diktat.plugin.maven\n\nimport com.saveourtool.diktat.api.DiktatReporterType\nimport org.apache.maven.project.MavenProject\nimport java.io.File\n\n/**\n * @param reporterType\n * @return default location of report with provided [reporterType]\n */\ninternal fun MavenProject.defaultReportLocation(\n    reporterType: DiktatReporterType,\n): File = basedir\n    .resolve(build.directory)\n    .resolve(\"reports\")\n    .resolve(\"diktat\")\n    .resolve(\"diktat.${reporterType.extension}\")\n"
  },
  {
    "path": "diktat-maven-plugin/src/main/kotlin/com/saveourtool/diktat/plugin/maven/reporters/DefaultReporter.kt",
    "content": "/**\n * All default reporters\n */\n\npackage com.saveourtool.diktat.plugin.maven.reporters\n\nimport com.saveourtool.diktat.api.DiktatReporterCreationArguments\nimport com.saveourtool.diktat.api.DiktatReporterType\nimport com.saveourtool.diktat.plugin.maven.defaultReportLocation\nimport org.apache.maven.plugins.annotations.Parameter\nimport org.apache.maven.project.MavenProject\nimport java.io.File\nimport java.nio.file.Path\n\n/**\n * A base interface for a default reporter\n *\n * @param type type of reporter\n */\nopen class DefaultReporter(\n    private val type: DiktatReporterType,\n) : Reporter {\n    /**\n     * Location for output\n     */\n    @Parameter\n    var output: File? = null\n\n    override fun getOutput(project: MavenProject): File? = output ?: project.defaultReportLocation(type)\n\n    override fun toCreationArguments(\n        project: MavenProject,\n        sourceRootDir: Path,\n    ): DiktatReporterCreationArguments = DiktatReporterCreationArguments(\n        reporterType = type,\n        outputStream = getOutputStream(project),\n        sourceRootDir = sourceRootDir.takeIf { type == DiktatReporterType.SARIF },\n    )\n}\n\n/**\n * Plain reporter\n */\nclass PlainReporter : DefaultReporter(\n    type = DiktatReporterType.PLAIN,\n) {\n    /**\n     * Plain reporter prints to stdout by default\n     */\n    override fun getOutput(project: MavenProject): File? = output\n}\n\n/**\n * JSON reporter\n */\nclass JsonReporter : DefaultReporter(\n    type = DiktatReporterType.JSON,\n)\n\n/**\n * SARIF reporter\n */\nclass SarifReporter : DefaultReporter(\n    type = DiktatReporterType.SARIF,\n)\n\n/**\n * Checkstyle reporter\n */\nclass CheckstyleReporter : DefaultReporter(\n    type = DiktatReporterType.CHECKSTYLE,\n)\n\n/**\n * HTML reporter\n */\nclass HtmlReporter : DefaultReporter(\n    type = DiktatReporterType.HTML,\n)\n"
  },
  {
    "path": "diktat-maven-plugin/src/main/kotlin/com/saveourtool/diktat/plugin/maven/reporters/GitHubActionsReporter.kt",
    "content": "package com.saveourtool.diktat.plugin.maven.reporters\n\nimport com.saveourtool.diktat.api.DiktatReporterCreationArguments\nimport com.saveourtool.diktat.api.DiktatReporterType\nimport com.saveourtool.diktat.plugin.maven.defaultReportLocation\nimport org.apache.maven.project.MavenProject\nimport java.io.File\nimport java.nio.file.Path\n\n/**\n * GitHub actions reporter\n */\nclass GitHubActionsReporter : Reporter {\n    override fun getOutput(project: MavenProject): File = project.defaultReportLocation(DiktatReporterType.SARIF)\n    override fun toCreationArguments(project: MavenProject, sourceRootDir: Path): DiktatReporterCreationArguments =\n        DiktatReporterCreationArguments(\n            reporterType = DiktatReporterType.SARIF,\n            outputStream = getOutputStream(project),\n            sourceRootDir = sourceRootDir,\n        )\n}\n"
  },
  {
    "path": "diktat-maven-plugin/src/main/kotlin/com/saveourtool/diktat/plugin/maven/reporters/Reporter.kt",
    "content": "package com.saveourtool.diktat.plugin.maven.reporters\n\nimport com.saveourtool.diktat.api.DiktatReporterCreationArguments\nimport org.apache.maven.project.MavenProject\nimport java.io.File\nimport java.io.OutputStream\nimport java.nio.file.Files\nimport java.nio.file.Path\n\n/**\n * A base interface for reporter\n */\ninterface Reporter {\n    /**\n     * @param project\n     * @return location as a [File] for output or default value resolved by [project]\n     */\n    fun getOutput(project: MavenProject): File?\n\n    /**\n     * @param project\n     * @return location as an [OutputStream] for output or default value resolved by [project]\n     */\n    fun getOutputStream(project: MavenProject): OutputStream? = getOutput(project)?.also { Files.createDirectories(it.parentFile.toPath()) }?.outputStream()\n\n    /**\n     * @param project\n     * @param sourceRootDir\n     * @return [DiktatReporterCreationArguments] to create this reporter\n     */\n    fun toCreationArguments(project: MavenProject, sourceRootDir: Path): DiktatReporterCreationArguments\n}\n"
  },
  {
    "path": "diktat-maven-plugin/src/main/kotlin/com/saveourtool/diktat/plugin/maven/reporters/Reporters.kt",
    "content": "package com.saveourtool.diktat.plugin.maven.reporters\n\nimport org.apache.maven.plugins.annotations.Parameter\n\n/**\n * Configuration for reporters\n */\nclass Reporters {\n    /**\n     * Configure *plain* reporter\n     */\n    @Parameter\n    var plain: PlainReporter? = null\n\n    /**\n     * Configure *json* reporter\n     */\n    @Parameter\n    var json: JsonReporter? = null\n\n    /**\n     * Configure *sarif* reporter\n     */\n    @Parameter\n    var sarif: SarifReporter? = null\n\n    /**\n     * Configure *sarif* reporter for GitHub actions\n     */\n    @Parameter\n    var gitHubActions: GitHubActionsReporter? = null\n\n    /**\n     * Configure *checkstyle* reporter\n     */\n    @Parameter\n    var checkstyle: CheckstyleReporter? = null\n\n    /**\n     * Configure *html* reporter\n     */\n    @Parameter\n    var html: HtmlReporter? = null\n\n    /**\n     * @return all configured reporters\n     */\n    fun getAll(): List<Reporter> = listOfNotNull(\n        plain,\n        json,\n        sarif,\n        gitHubActions,\n        checkstyle,\n        html,\n    )\n}\n"
  },
  {
    "path": "diktat-maven-plugin/src/test/kotlin/com/saveourtool/diktat/plugin/maven/DiktatBaseMojoTest.kt",
    "content": "package com.saveourtool.diktat.plugin.maven\n\nimport org.apache.maven.execution.DefaultMavenExecutionRequest\nimport org.apache.maven.plugin.MojoExecutionException\nimport org.apache.maven.plugin.testing.MojoRule\nimport org.apache.maven.project.ProjectBuilder\nimport org.apache.maven.project.ProjectBuildingRequest\nimport org.eclipse.aether.DefaultRepositorySystemSession\nimport org.junit.Before\nimport org.junit.Ignore\nimport org.junit.Rule\nimport org.junit.Test\nimport org.junit.jupiter.api.Assertions\nimport kotlin.io.path.Path\nimport kotlin.io.path.createTempFile\nimport kotlin.io.path.div\n\n/**\n * Tests for mojo configuration. NB: this tests are using Junit4, because maven-plugin-testing-harness doesn't support 5.\n */\n@Suppress(\"LongMethod\", \"TOO_LONG_FUNCTION\")\n@Ignore\nclass DiktatBaseMojoTest {\n    @get:Rule val mojoRule = MojoRule()\n    private lateinit var buildingRequest: ProjectBuildingRequest\n    private lateinit var projectBuilder: ProjectBuilder\n\n    /**\n     * Initialize properties needed to create mavenProject stub able to resolve maven parameters.\n     */\n    @Before\n    fun setUp() {\n        val executionRequest = DefaultMavenExecutionRequest()\n        buildingRequest = executionRequest.projectBuildingRequest.apply {\n            repositorySession = DefaultRepositorySystemSession()\n        }\n        projectBuilder = mojoRule.lookup(ProjectBuilder::class.java)\n    }\n\n    @Test\n    fun `test default plugin configuration`() {\n        val pom = createTempFile().toFile()\n        pom.writeText(\n            \"\"\"\n                <project xmlns=\"http://maven.apache.org/POM/4.0.0\"\n                        xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n                        xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n                    <modelVersion>4.0.0</modelVersion>\n\n                    <groupId>com.saveourtool.diktat</groupId>\n                    <artifactId>diktat-test</artifactId>\n                    <version>1.0.0-SNAPSHOT</version>\n\n                    <build>\n                        <plugins>\n                            <plugin>\n                                <groupId>com.saveourtool.diktat</groupId>\n                                <artifactId>diktat-maven-plugin</artifactId>\n                                <executions>\n                                    <execution>\n                                        <goals>\n                                            <goal>check</goal>\n                                        </goals>\n                                    </execution>\n                                </executions>\n                            </plugin>\n                        </plugins>\n                    </build>\n                </project>\n            \"\"\".trimIndent()\n        )\n        val mavenProject = projectBuilder.build(pom, buildingRequest).project\n\n        val diktatCheckMojo = mojoRule.lookupConfiguredMojo(mavenProject, \"check\") as DiktatCheckMojo\n        Assertions.assertEquals(\"diktat-analysis.yml\", diktatCheckMojo.diktatConfigFile)\n        Assertions.assertIterableEquals(listOf(pom.parentFile.toPath() / \"src\"), diktatCheckMojo.inputs.map { Path(it) })\n        Assertions.assertTrue(diktatCheckMojo.excludes.isEmpty())\n    }\n\n    @Test\n    fun `test plugin custom configuration`() {\n        val pom = createTempFile().toFile()\n        pom.writeText(\n            \"\"\"\n                <project xmlns=\"http://maven.apache.org/POM/4.0.0\"\n                        xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n                        xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n                    <modelVersion>4.0.0</modelVersion>\n\n                    <groupId>com.saveourtool.diktat</groupId>\n                    <artifactId>diktat-test</artifactId>\n                    <version>1.0.0-SNAPSHOT</version>\n\n                    <build>\n                        <plugins>\n                            <plugin>\n                                <groupId>com.saveourtool.diktat</groupId>\n                                <artifactId>diktat-maven-plugin</artifactId>\n                                <configuration>\n                                    <diktatConfigFile>my-diktat-config.yml</diktatConfigFile>\n                                    <inputs>\n                                        <input>${'$'}{project.basedir}/src/main/kotlin</input>\n                                        <input>${'$'}{project.basedir}/src/test/kotlin</input>\n                                    </inputs>\n                                    <excludes>\n                                        <exclude>${'$'}{project.basedir}/src/main/kotlin/exclusion</exclude>\n                                    </excludes>\n                                </configuration>\n                                <executions>\n                                    <execution>\n                                        <goals>\n                                            <goal>check</goal>\n                                        </goals>\n                                    </execution>\n                                </executions>\n                            </plugin>\n                        </plugins>\n                    </build>\n                </project>\n            \"\"\".trimIndent()\n        )\n        val mavenProject = projectBuilder.build(pom, buildingRequest).project\n\n        val diktatCheckMojo = mojoRule.lookupConfiguredMojo(mavenProject, \"check\") as DiktatCheckMojo\n        Assertions.assertEquals(\"my-diktat-config.yml\", diktatCheckMojo.diktatConfigFile)\n        Assertions.assertIterableEquals(\n            listOf(pom.parentFile.toPath() / \"src/main/kotlin\", pom.parentFile.toPath() / \"src/test/kotlin\"),\n            diktatCheckMojo.inputs.map { Path(it) }\n        )\n        Assertions.assertIterableEquals(\n            listOf(pom.parentFile.toPath() / \"src/main/kotlin/exclusion\"),\n            diktatCheckMojo.excludes.map { Path(it) }\n        )\n        val mojoExecutionException = Assertions.assertThrows(MojoExecutionException::class.java) {\n            diktatCheckMojo.execute()\n        }\n        Assertions.assertEquals(\"Configuration file my-diktat-config.yml doesn't exist\",\n            mojoExecutionException.message)\n    }\n}\n"
  },
  {
    "path": "diktat-maven-plugin/src/test/kotlin/com/saveourtool/diktat/plugin/maven/DiktatMavenPluginIntegrationTest.kt",
    "content": "package com.saveourtool.diktat.plugin.maven\n\nimport com.soebes.itf.jupiter.extension.MavenGoal\nimport com.soebes.itf.jupiter.extension.MavenJupiterExtension\nimport com.soebes.itf.jupiter.extension.MavenTest\nimport com.soebes.itf.jupiter.maven.MavenExecutionResult\nimport org.assertj.core.api.Assertions.assertThat\nimport org.assertj.core.api.SoftAssertions\nimport org.junit.jupiter.api.Assertions\nimport org.junit.jupiter.api.BeforeEach\nimport org.junit.jupiter.api.TestInfo\nimport java.io.File\nimport kotlin.io.path.Path\nimport kotlin.io.path.deleteIfExists\nimport kotlin.io.path.div\nimport kotlin.io.path.readText\n\n/**\n * Integration tests for diktat-maven-plugin. Run against the project from diktat-examples.\n * The whole pipeline is as follows:\n * * For each test case, test data is copied from examples with respect to maven-itf requirements, .mvn/jvm.config and .mvn/maven.config are copied, too.\n *   **Note**: for maven-itf-plugin, test name should equal example project's directory name, which we have in `pom.xml`.\n * * maven-failsafe-plugin launches tests; for each test case a separate maven process is spawned. `diktat.version` is taken from `.mvn/maven.config`\n *   and the exact value is written when maven copies resources.\n * * maven execution results are analyzed here; `.mvn/jvm.config` is used to attach jacoco java agent to every maven process and generate individual execution reports.\n *\n * When within an IDE (e.g.: _IDEA_), don't run this test directly: it's\n * expected to be executed from a forked JVM. Instead, run a `verify` _lifecycle\n * phase_ for the `diktat-maven-plugin` submodule, as if you were running\n *\n * ```console\n * $ mvn -pl diktat-maven-plugin verify\n * ```\n *\n * from your terminal. If multiple JDKs are installed, be sure to pass\n * `JAVA_HOME` to the _run configuration_, so that the parent and the forked\n * JVMs have the same version.\n */\n@MavenJupiterExtension\nclass DiktatMavenPluginIntegrationTest {\n    @BeforeEach\n    fun beforeEach(testInfo: TestInfo) {\n        val method = testInfo.testMethod.orElse(null) ?: return\n\n        (Path(\"target\") / \"jacoco-it-${method.name}.exec\").deleteIfExists()\n    }\n\n    @MavenTest\n    @MavenGoal(\"diktat:check@diktat\")\n    fun diktatCheck(testInfo: TestInfo, result: MavenExecutionResult) {\n        Assertions.assertEquals(1, result.returnCode)\n        Assertions.assertFalse(result.isSuccessful)\n        Assertions.assertTrue(result.isFailure)\n\n        val mavenLog = result.mavenLog.stdout.readText()\n\n        assertThat(mavenLog).contains(\"[FILE_NAME_MATCH_CLASS]\")\n\n        val method = testInfo.testMethod.get()\n        File(result.mavenProjectResult.targetProjectDirectory.toFile(), \"target/jacoco-it.exec\").copyTo(\n            File(\"target/jacoco-it-${method.name}.exec\")\n        )\n    }\n\n    @MavenTest\n    @MavenGoal(\"diktat:fix@diktat\")\n    fun diktatFix(testInfo: TestInfo, result: MavenExecutionResult) {\n        Assertions.assertEquals(1, result.returnCode)\n        Assertions.assertFalse(result.isSuccessful)\n        Assertions.assertTrue(result.isFailure)\n\n        val mavenLog = result.mavenLog.stdout.readText()\n\n        with(SoftAssertions()) {\n            try {\n                assertThat(mavenLog).containsPattern(\"\"\"Original and formatted content differ, writing to [:\\w/\\\\-]+Test\\.kt\\.\\.\\.\"\"\")\n                assertThat(mavenLog).containsPattern(\"There are \\\\d+ lint errors\")\n                assertThat(mavenLog).contains(\"[MISSING_KDOC_TOP_LEVEL]\")\n            } finally {\n                assertAll()\n            }\n        }\n\n        val method = testInfo.testMethod.get()\n        File(result.mavenProjectResult.targetProjectDirectory.toFile(), \"target/jacoco-it.exec\").copyTo(\n            File(\"target/jacoco-it-${method.name}.exec\")\n        )\n    }\n}\n"
  },
  {
    "path": "diktat-maven-plugin/src/test/resources/.mvn/jvm.config",
    "content": "-javaagent:${settings.localRepository}/org/jacoco/org.jacoco.agent/${jacoco.version}/org.jacoco.agent-${jacoco.version}-runtime.jar=destfile=target/jacoco-it.exec,includes=com.saveourtool.diktat.plugin.maven.*\n"
  },
  {
    "path": "diktat-maven-plugin/src/test/resources/.mvn/maven.config",
    "content": "-Ddiktat.version=${project.version}"
  },
  {
    "path": "diktat-rules/build.gradle.kts",
    "content": "@Suppress(\"DSL_SCOPE_VIOLATION\", \"RUN_IN_SCRIPT\")  // https://github.com/gradle/gradle/issues/22797\nplugins {\n    id(\"com.saveourtool.diktat.buildutils.kotlin-jvm-configuration\")\n    id(\"com.saveourtool.diktat.buildutils.code-quality-convention\")\n    id(\"com.saveourtool.diktat.buildutils.publishing-default-configuration\")\n    alias(libs.plugins.kotlin.ksp)\n    idea\n}\n\nproject.description = \"The main diktat ruleset\"\n\ndependencies {\n    api(projects.diktatApi)\n    implementation(libs.kotlin.stdlib.jdk8)\n    implementation(libs.kotlin.compiler.embeddable)\n    // kaml is used to read configs from YAML file\n    implementation(libs.kaml)\n    // guava is used for string case utils\n    implementation(libs.guava)\n    implementation(libs.kotlin.logging)\n    testImplementation(projects.diktatCommonTest)\n    testImplementation(projects.diktatKtlintEngine)\n    testImplementation(libs.log4j2.slf4j2)\n    testImplementation(libs.junit.jupiter)\n    testImplementation(libs.junit.platform.suite)\n    testImplementation(libs.assertj.core)\n    // is used for simplifying boolean expressions\n    implementation(libs.jbool.expressions)\n\n    // generating\n    compileOnly(projects.diktatDevKsp)\n    ksp(projects.diktatDevKsp)\n    testImplementation(libs.kotlin.reflect)\n}\n\nproject.afterEvaluate {\n    tasks.named(\"kspKotlin\") {\n        // not clear issue that :kspKotlin is up-to-date, but generated files are missed\n        outputs.upToDateWhen { false }\n    }\n    tasks.named(\"test\") {\n        dependsOn(tasks.named(\"kspKotlin\"))\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/main/kotlin/com/saveourtool/diktat/common/config/rules/LegacyUtils.kt",
    "content": "/**\n * This file contains aliases to support old names and util methods\n */\n\npackage com.saveourtool.diktat.common.config.rules\n\nimport com.saveourtool.diktat.api.DiktatRuleConfig\nimport com.saveourtool.diktat.api.DiktatRuleNameAware\nimport com.saveourtool.diktat.api.findByRuleName\n\n/**\n * Name of common configuration\n */\nconst val DIKTAT_COMMON = \"DIKTAT_COMMON\"\n\ntypealias RuleConfiguration = com.saveourtool.diktat.ruleset.config.RuleConfiguration\ntypealias CommonConfiguration = com.saveourtool.diktat.ruleset.config.CommonConfiguration\n\n/**\n * Get [DiktatRuleConfig] for particular [DiktatRuleNameAware] object.\n *\n * @param rule a [DiktatRuleNameAware] which configuration will be returned\n * @return [DiktatRuleConfig] for a particular rule if it is found, else null\n */\nfun List<DiktatRuleConfig>.getRuleConfig(rule: DiktatRuleNameAware): DiktatRuleConfig? = this.findByRuleName(rule)\n\n/**\n * @return common configuration from list of all rules configuration\n */\nfun List<DiktatRuleConfig>.getCommonConfiguration(): CommonConfiguration = CommonConfiguration(getCommonConfig()?.configuration)\n\n/**\n * Get [DiktatRuleConfig] representing common configuration part that can be used in any rule\n */\nprivate fun List<DiktatRuleConfig>.getCommonConfig() = find { it.name == DIKTAT_COMMON }\n"
  },
  {
    "path": "diktat-rules/src/main/kotlin/com/saveourtool/diktat/ruleset/config/AbstractDiktatRuleConfigReader.kt",
    "content": "package com.saveourtool.diktat.ruleset.config\n\nimport com.saveourtool.diktat.api.DiktatRuleConfig\nimport com.saveourtool.diktat.api.DiktatRuleConfigReader\nimport com.saveourtool.diktat.common.config.rules.DIKTAT_COMMON\nimport com.saveourtool.diktat.ruleset.constants.Warnings\nimport io.github.oshai.kotlinlogging.KotlinLogging\nimport org.jetbrains.kotlin.org.jline.utils.Levenshtein\nimport java.io.IOException\nimport java.io.InputStream\nimport kotlin.jvm.Throws\n\n/**\n * This class is used to read input stream in any format that you will specify.\n * Usage:\n * 1) implement this class with implementing the method:\n *    a. parse - implement parser for your file format (for example parse it to a proper json)\n * 2) Use your new class MyReader().read(someInputStream)\n */\nabstract class AbstractDiktatRuleConfigReader : DiktatRuleConfigReader {\n    /**\n     * @param inputStream - input stream\n     * @return list of [DiktatRuleConfig] if resource has been parsed successfully\n     */\n    override fun invoke(inputStream: InputStream): List<DiktatRuleConfig> =\n        read(inputStream)?.onEach(::validate).orEmpty()\n\n    private fun read(inputStream: InputStream): List<DiktatRuleConfig>? = try {\n        parse(inputStream)\n    } catch (e: IOException) {\n        log.error(e) {\n            \"Cannot read config from input stream due to: \"\n        }\n        null\n    }\n\n    /**\n     * you can specify your own parser, in example for parsing stream as a json\n     *\n     * @param inputStream a [InputStream] representing loaded content\n     * @return resource parsed as list of [DiktatRuleConfig]\n     * @throws IOException\n     */\n    @Throws(IOException::class)\n    protected abstract fun parse(inputStream: InputStream): List<DiktatRuleConfig>\n\n    private fun validate(config: DiktatRuleConfig) =\n        require(config.name == DIKTAT_COMMON || config.name in Warnings.names) {\n            val closestMatch = Warnings.names.minByOrNull { Levenshtein.distance(it, config.name) }\n            \"Warning name <${config.name}> in configuration file is invalid, did you mean <$closestMatch>?\"\n        }\n\n    companion object {\n        private val log = KotlinLogging.logger {}\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/main/kotlin/com/saveourtool/diktat/ruleset/config/CommonConfiguration.kt",
    "content": "package com.saveourtool.diktat.ruleset.config\n\nimport io.github.oshai.kotlinlogging.KLogger\nimport io.github.oshai.kotlinlogging.KotlinLogging\nimport java.util.Locale\nimport java.util.concurrent.atomic.AtomicInteger\n\n/**\n * class returns the list of common configurations that we have read from a configuration map\n *\n * @param configuration map of common configuration\n */\ndata class CommonConfiguration(private val configuration: Map<String, String>?) {\n    /**\n     * List of directory names which will be used to detect test sources\n     */\n    val testAnchors: List<String> by lazy {\n        val testDirs = (configuration ?: emptyMap()).getOrDefault(\"testDirs\", \"test\").split(',').map { it.trim() }\n        if (testDirs.any { !it.lowercase(Locale.getDefault()).endsWith(\"test\") }) {\n            log.error { \"test directory names should end with `test`\" }\n        }\n        testDirs\n    }\n\n    /**\n     * Start of package name, which shoould be common, e.g. org.example.myproject\n     */\n    val domainName: String? by lazy {\n        configuration?.get(\"domainName\")\n    }\n\n    /**\n     * Get disable chapters from configuration\n     */\n    val disabledChapters: String? by lazy {\n        configuration?.get(\"disabledChapters\")\n    }\n\n    /**\n     * Get version of kotlin from configuration\n     */\n    val kotlinVersion: KotlinVersion by lazy {\n        configuration?.get(\"kotlinVersion\")?.kotlinVersion() ?: run {\n            if (visitorCounter.incrementAndGet() == 1) {\n                log.error { \"Kotlin version not specified in the configuration file. Will be using ${KotlinVersion.CURRENT} version\" }\n            }\n            KotlinVersion.CURRENT\n        }\n    }\n\n    /**\n     * Get source directories from configuration\n     */\n    val srcDirectories: List<String> by lazy {\n        configuration?.get(\"srcDirectories\")?.split(\",\")?.map { it.trim() } ?: listOf(\"main\")\n    }\n\n    companion object {\n        internal val log: KLogger = KotlinLogging.logger {}\n\n        /**\n         * Counter that helps not to raise multiple warnings about kotlin version\n         */\n        var visitorCounter = AtomicInteger(0)\n    }\n}\n\n/**\n * Parse string into KotlinVersion\n *\n * @return KotlinVersion from configuration\n */\ninternal fun String.kotlinVersion(): KotlinVersion {\n    require(this.contains(\"^(\\\\d+\\\\.)(\\\\d+)\\\\.?(\\\\d+)?$\".toRegex())) {\n        \"Kotlin version format is incorrect\"\n    }\n    val versions = this.split(\".\").map { it.toInt() }\n    return if (versions.size == 2) {\n        KotlinVersion(versions[0], versions[1])\n    } else {\n        KotlinVersion(versions[0], versions[1], versions[2])\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/main/kotlin/com/saveourtool/diktat/ruleset/config/DiktatRuleConfigYamlReader.kt",
    "content": "package com.saveourtool.diktat.ruleset.config\n\nimport com.saveourtool.diktat.common.config.rules.RulesConfig\nimport com.charleskorn.kaml.Yaml\nimport com.charleskorn.kaml.YamlConfiguration\nimport com.charleskorn.kaml.decodeFromStream\nimport java.io.InputStream\n\n/**\n * class returns the list of configurations that we have read from a yml: diktat-analysis.yml\n */\nclass DiktatRuleConfigYamlReader : AbstractDiktatRuleConfigReader() {\n    private val yamlSerializer by lazy { Yaml(configuration = YamlConfiguration(strictMode = true)) }\n\n    /**\n     * Parse resource file into list of [RulesConfig]\n     *\n     * @param inputStream a [InputStream] representing loaded rules config file\n     * @return list of [RulesConfig]\n     */\n    override fun parse(inputStream: InputStream): List<RulesConfig> = yamlSerializer.decodeFromStream<List<RulesConfig>>(inputStream)\n}\n"
  },
  {
    "path": "diktat-rules/src/main/kotlin/com/saveourtool/diktat/ruleset/config/RuleConfiguration.kt",
    "content": "package com.saveourtool.diktat.ruleset.config\n\n/**\n * Configuration that allows customizing additional options of particular rules.\n * @property config a map of strings with configuration options for a particular rule\n */\nopen class RuleConfiguration(protected val config: Map<String, String>)\n"
  },
  {
    "path": "diktat-rules/src/main/kotlin/com/saveourtool/diktat/ruleset/constants/Chapters.kt",
    "content": "package com.saveourtool.diktat.ruleset.constants\n\nimport com.saveourtool.diktat.common.config.rules.RulesConfig\nimport com.saveourtool.diktat.common.config.rules.getCommonConfiguration\nimport com.saveourtool.diktat.ruleset.utils.isDigits\nimport org.jetbrains.kotlin.org.jline.utils.Levenshtein\n\n/**\n * This class represents the chapters that are in our code style.\n *\n * @property number - number of chapter\n * @property title name of chapter\n */\n@Suppress(\"WRONG_DECLARATIONS_ORDER\")\nenum class Chapters(val number: String, val title: String) {\n    DUMMY(\"0\", \"Dummy\"),\n    NAMING(\"1\", \"Naming\"),\n    COMMENTS(\"2\", \"Comments\"),\n    TYPESETTING(\"3\", \"General\"),\n    VARIABLES(\"4\", \"Variables\"),\n    FUNCTIONS(\"5\", \"Functions\"),\n    CLASSES(\"6\", \"Classes\"),\n    ;\n}\n\n/**\n * Function checks if warning from enable chapter\n *\n * @param configRules list of rules configuration\n * @return is warning from enable chapter\n */\nfun Warnings.isRuleFromActiveChapter(configRules: List<RulesConfig>): Boolean {\n    val chapterFromRule = getChapterByWarning()\n    val configuration = configRules.getCommonConfiguration()\n    val disabledChapters = configuration.disabledChapters\n        ?.takeIf { it.isNotBlank() }\n        ?.split(\",\")\n        ?.map { it.trim() }\n        ?.mapNotNull { chap ->\n            if (chap.isDigits()) {\n                Chapters.values().find { chap == it.number }\n            } else {\n                validate(chap)\n                Chapters.values().find { it.title == chap }\n            }\n        }\n    return disabledChapters?.let { return chapterFromRule !in it } ?: true\n}\n\n/**\n * Function get chapter by warning\n *\n * @return chapter to which warning refers\n */\n@Suppress(\"UnsafeCallOnNullableType\")\nfun Warnings.getChapterByWarning() = Chapters.values().find { it.number == this.ruleId.first().toString() }!!\n\nprivate fun validate(chapter: String) =\n    require(chapter in Chapters.values().map { it.title }) {\n        val closestMatch = Chapters.values().minByOrNull { Levenshtein.distance(it.title, chapter) }\n        \"Chapter name <$chapter> in configuration file is invalid, did you mean <$closestMatch>?\"\n    }\n"
  },
  {
    "path": "diktat-rules/src/main/kotlin/com/saveourtool/diktat/ruleset/constants/Warnings.kt",
    "content": "package com.saveourtool.diktat.ruleset.constants\n\nimport com.saveourtool.diktat.api.DiktatErrorEmitter\nimport com.saveourtool.diktat.api.isRuleEnabled\nimport com.saveourtool.diktat.common.config.rules.Rule\nimport com.saveourtool.diktat.common.config.rules.RulesConfig\nimport com.saveourtool.diktat.ruleset.generation.EnumNames\nimport com.saveourtool.diktat.ruleset.utils.isSuppressed\nimport org.jetbrains.kotlin.com.intellij.lang.ASTNode\n\n/**\n * This class represent individual inspections of diktat code style.\n * A [Warnings] entry contains rule name, warning message and is used in code check.\n *\n * @param warn description of the inspection\n * @property canBeAutoCorrected whether this inspection can automatically fix the code. Should be public to be able to use it in docs generator.\n * @property ruleId number of the inspection according to [diktat code style](https://github.com/saveourtool/diktat/blob/master/info/guide/diktat-coding-convention.md)\n */\n@Suppress(\n    \"ForbiddenComment\",\n    \"MagicNumber\",\n    \"WRONG_DECLARATIONS_ORDER\",\n    \"MaxLineLength\",\n    \"WRONG_NEWLINES\"\n)\n@EnumNames(\n    generatedPackageName = \"generated\",\n    generatedClassName = \"WarningNames\",\n)\nenum class Warnings(\n    @Suppress(\"PRIVATE_MEMBER\") val canBeAutoCorrected: Boolean,\n    val ruleId: String,\n    private val warn: String) : Rule {\n    // ======== dummy test warning ======\n    DUMMY_TEST_WARNING(true, \"0.0.0\", \"this is a dummy warning that can be used for manual testing of fixer/checker\"),\n\n    // ======== chapter 1 ========\n    PACKAGE_NAME_MISSING(true, \"1.2.1\", \"no package name declared in a file\"),\n    PACKAGE_NAME_INCORRECT_CASE(true, \"1.2.1\", \"package name should be completely in a lower case\"),\n    PACKAGE_NAME_INCORRECT_PREFIX(true, \"1.2.1\", \"package name should start from company's domain\"),\n\n    // FixMe: should add autofix\n    PACKAGE_NAME_INCORRECT_SYMBOLS(false, \"1.2.1\", \"package name should contain only latin (ASCII) letters or numbers. For separation of words use dot\"),\n    PACKAGE_NAME_INCORRECT_PATH(true, \"1.2.1\", \"package name does not match the directory hierarchy for this file, the real package name should be\"),\n    INCORRECT_PACKAGE_SEPARATOR(true, \"1.2.1\", \"package name parts should be separated only by dots - there should be no other symbols like underscores (_)\"),\n    CLASS_NAME_INCORRECT(true, \"1.3.1\", \"class/enum/interface name should be in PascalCase and should contain only latin (ASCII) letters or numbers\"),\n    OBJECT_NAME_INCORRECT(true, \"1.3.1\", \"object structure name should be in PascalCase and should contain only latin (ASCII) letters or numbers\"),\n    VARIABLE_NAME_INCORRECT_FORMAT(true, \"1.6.1\",\n        \"variable name should be in lowerCamelCase and should contain only latin (ASCII) letters or numbers and should start from lower letter\"),\n    VARIABLE_NAME_INCORRECT(false, \"1.1.1\", \"variable name should contain more than one letter\"),\n    CONSTANT_UPPERCASE(true, \"1.5.1\", \"<val> properties from companion object or on file level mostly in all cases are constants - please use upper snake case for them\"),\n    VARIABLE_HAS_PREFIX(true, \"1.1.1\", \"variable has prefix (like mVariable or M_VARIABLE), generally it is a bad code style (Android - is the only exception)\"),\n    IDENTIFIER_LENGTH(false, \"1.1.1\", \"identifier's length is incorrect, it should be in range of [2, 64] symbols\"),\n    ENUM_VALUE(true, \"1.3.1\", \"enum values should be in a proper format/case\"),\n    GENERIC_NAME(true, \"1.1.1\", \"generic name should contain only one single capital letter, it can be followed by a number\"),\n    BACKTICKS_PROHIBITED(false, \"1.1.1\", \"backticks should not be used in identifier's naming. The only exception test methods marked with @Test annotation\"),\n    FUNCTION_NAME_INCORRECT_CASE(true, \"1.4.1\", \"function/method name should be in lowerCamelCase\"),\n    TYPEALIAS_NAME_INCORRECT_CASE(true, \"1.3.1\", \"typealias name should be in pascalCase\"),\n    FUNCTION_BOOLEAN_PREFIX(true, \"1.6.2\", \"functions that return the value of Boolean type should have <is> or <has> prefix\"),\n    FILE_NAME_INCORRECT(true, \"1.1.1\", \"file name is incorrect - it should end with .kt extension and be in PascalCase\"),\n    EXCEPTION_SUFFIX(true, \"1.1.1\", \"all exception classes should have \\\"Exception\\\" suffix\"),\n    CONFUSING_IDENTIFIER_NAMING(false, \"1.1.1\", \"it's a bad name for identifier\"),\n\n    // ======== chapter 2 ========\n    MISSING_KDOC_TOP_LEVEL(false, \"2.1.1\", \"all public and internal top-level classes and functions should have Kdoc\"),\n    MISSING_KDOC_CLASS_ELEMENTS(false, \"2.1.1\", \"all public, internal and protected classes, functions and variables inside the class should have Kdoc\"),\n    MISSING_KDOC_ON_FUNCTION(true, \"2.1.1\", \"all public, internal and protected functions should have Kdoc with proper tags\"),\n    KDOC_TRIVIAL_KDOC_ON_FUNCTION(false, \"2.3.1\", \"KDocs should not be trivial (e.g. method getX should not de documented as 'returns X')\"),\n    KDOC_WITHOUT_PARAM_TAG(true, \"2.1.2\", \"all methods which take arguments should have @param tags in KDoc\"),\n    KDOC_WITHOUT_RETURN_TAG(true, \"2.1.2\", \"all methods which return values should have @return tag in KDoc\"),\n    KDOC_WITHOUT_THROWS_TAG(true, \"2.1.2\", \"all methods which throw exceptions should have @throws tag in KDoc\"),\n    KDOC_EMPTY_KDOC(false, \"2.1.3\", \"KDoc should never be empty\"),\n    KDOC_WRONG_SPACES_AFTER_TAG(true, \"2.1.3\", \"there should be exactly one white space after tag name in KDoc\"),\n    KDOC_WRONG_TAGS_ORDER(true, \"2.1.3\", \"in KDoc standard tags are arranged in this order: @receiver, @param, @property, @return, @throws or @exception, @constructor, but are\"),\n    KDOC_NEWLINES_BEFORE_BASIC_TAGS(true, \"2.1.3\",\n        \"in KDoc block of standard tags @param, @return, @throws should contain newline before only if there is other content before it\"),\n    KDOC_NO_NEWLINES_BETWEEN_BASIC_TAGS(true, \"2.1.3\", \"in KDoc standard tags @param, @return, @throws should not containt newline between them, but these tags do\"),\n    KDOC_NO_NEWLINE_AFTER_SPECIAL_TAGS(true, \"2.1.3\", \"in KDoc there should be exactly one empty line after special tags\"),\n    KDOC_NO_EMPTY_TAGS(false, \"2.2.1\", \"no empty descriptions in tag blocks are allowed\"),\n    KDOC_NO_DEPRECATED_TAG(true, \"2.1.3\", \"KDoc doesn't support @deprecated tag, use @Deprecated annotation instead\"),\n    KDOC_NO_CONSTRUCTOR_PROPERTY(true, \"2.1.1\", \"all properties from the primary constructor should be documented in a @property tag in KDoc\"),\n    KDOC_NO_CLASS_BODY_PROPERTIES_IN_HEADER(true, \"2.1.1\", \"only properties from the primary constructor should be documented in a @property tag in class KDoc\"),\n    KDOC_EXTRA_PROPERTY(false, \"2.1.1\", \"There is property in KDoc which is not present in the class\"),\n    KDOC_DUPLICATE_PROPERTY(false, \"2.1.1\", \"There's a property in KDoc which is already present\"),\n    KDOC_NO_CONSTRUCTOR_PROPERTY_WITH_COMMENT(true, \"2.1.1\", \"replace comment before property with @property tag in class KDoc\"),\n    KDOC_CONTAINS_DATE_OR_AUTHOR(false, \"2.1.3\", \"KDoc should not contain creation date and author name\"),\n    HEADER_WRONG_FORMAT(true, \"2.2.1\", \"file header comments should be properly formatted\"),\n    HEADER_MISSING_OR_WRONG_COPYRIGHT(true, \"2.2.1\", \"file header comment must include copyright information inside a block comment\"),\n    WRONG_COPYRIGHT_YEAR(true, \"2.2.1\", \"year defined in copyright and current year are different\"),\n    HEADER_MISSING_IN_NON_SINGLE_CLASS_FILE(false, \"2.2.1\", \"files that contain multiple or no classes should contain description of what is inside of this file\"),\n    HEADER_NOT_BEFORE_PACKAGE(true, \"2.2.1\", \"header KDoc should be placed before package and imports\"),\n    COMMENTED_OUT_CODE(false, \"2.4.2\", \"you should not comment out code, use VCS to save it in history and delete this block\"),\n    COMMENTED_BY_KDOC(true, \"2.1.1\", \"you should not comment inside code blocks using kdoc syntax\"),\n    WRONG_NEWLINES_AROUND_KDOC(true, \"2.4.1\", \"there should be a blank line above the kDoc and there should not be no blank lines after kDoc\"),\n    FIRST_COMMENT_NO_BLANK_LINE(true, \"2.4.1\", \"there should not be any blank lines before first comment\"),\n    COMMENT_WHITE_SPACE(true, \"2.4.1\", \"there should be a white space between code and comment also between code start token and comment text\"),\n    IF_ELSE_COMMENTS(true, \"2.4.1\", \"invalid comments structure. Comment should be inside the block\"),\n\n    // ======== chapter 3 ========\n    FILE_IS_TOO_LONG(false, \"3.1.1\", \"file has more number of lines than expected\"),\n    FILE_CONTAINS_ONLY_COMMENTS(false, \"3.1.2\", \"empty files or files that contain only comments should be avoided\"),\n    FILE_INCORRECT_BLOCKS_ORDER(true, \"3.1.2\", \"general structure of kotlin source file is wrong, parts are in incorrect order\"),\n    FILE_NO_BLANK_LINE_BETWEEN_BLOCKS(true, \"3.1.2\", \"general structure of kotlin source file is wrong, general code blocks should be separated by empty lines\"),\n    FILE_UNORDERED_IMPORTS(true, \"3.1.2\", \"imports should be ordered alphabetically and shouldn't be separated by newlines\"),\n    FILE_WILDCARD_IMPORTS(false, \"3.1.2\", \"wildcard imports should not be used\"),\n    UNUSED_IMPORT(true, \"3.1.2\", \"unused imports should be removed\"),\n    NO_BRACES_IN_CONDITIONALS_AND_LOOPS(true, \"3.2.1\", \"in if, else, when, for, do, and while statements braces should be used. Exception: single line ternary operator statement\"),\n    WRONG_ORDER_IN_CLASS_LIKE_STRUCTURES(true, \"3.1.4\", \"the declaration part of a class-like code structures (class/interface/etc.) should be in the proper order\"),\n    BLANK_LINE_BETWEEN_PROPERTIES(true, \"3.1.4\", \"there should be no blank lines between properties without comments; comment, KDoc or annotation on property should have blank\" +\n            \" line before\"),\n    TOP_LEVEL_ORDER(true, \"3.1.5\", \"the declaration part of a top level elements should be in the proper order\"),\n    BRACES_BLOCK_STRUCTURE_ERROR(true, \"3.2.2\", \"braces should follow 1TBS style\"),\n    WRONG_INDENTATION(true, \"3.3.1\", \"only spaces are allowed for indentation and each indentation should equal to 4 spaces (tabs are not allowed)\"),\n    EMPTY_BLOCK_STRUCTURE_ERROR(true, \"3.4.1\", \"incorrect format of empty block\"),\n    MORE_THAN_ONE_STATEMENT_PER_LINE(true, \"3.6.1\", \"there should not be more than one code statement in one line\"),\n    LONG_LINE(true, \"3.5.1\", \"this line is longer than allowed\"),\n    REDUNDANT_SEMICOLON(true, \"3.6.2\", \"there should be no redundant semicolon at the end of lines\"),\n    WRONG_NEWLINES(true, \"3.6.2\", \"incorrect line breaking\"),\n    TRAILING_COMMA(true, \"3.6.2\", \"use trailing comma\"),\n    COMPLEX_EXPRESSION(false, \"3.6.3\", \"complex dot qualified expression should be replaced with variable\"),\n    COMPLEX_BOOLEAN_EXPRESSION(true, \"3.6.4\", \"simplification could be produced for the too complex boolean expression\"),\n\n    // FixMe: autofixing will be added for this rule\n    STRING_CONCATENATION(true, \"3.15.1\", \"strings should not be concatenated using plus operator - use string templates instead if the statement fits one line\"),\n    TOO_MANY_BLANK_LINES(true, \"3.7.1\", \"too many consecutive blank lines\"),\n    WRONG_WHITESPACE(true, \"3.8.1\", \"incorrect usage of whitespaces for code separation\"),\n    TOO_MANY_CONSECUTIVE_SPACES(true, \"3.8.1\", \"too many consecutive spaces\"),\n    ANNOTATION_NEW_LINE(true, \"3.12.1\", \"annotations must be on new line\"),\n    PREVIEW_ANNOTATION(true, \"3.12.2\", \"method, annotated with `@Preview` annotation should be private and has `Preview` suffix\"),\n    ENUMS_SEPARATED(true, \"3.9.1\", \"enum is incorrectly formatted\"),\n    WHEN_WITHOUT_ELSE(true, \"3.11.1\", \"each 'when' statement must have else at the end\"),\n    LONG_NUMERICAL_VALUES_SEPARATED(true, \"3.14.2\", \"long numerical values should be separated with underscore\"),\n    MAGIC_NUMBER(false, \"3.14.3\", \"avoid using magic numbers, instead define constants with clear names describing what the magic number means\"),\n    WRONG_DECLARATIONS_ORDER(true, \"3.1.4\", \"declarations of constants and enum members should be sorted alphabetically\"),\n    WRONG_MULTIPLE_MODIFIERS_ORDER(true, \"3.14.1\", \"sequence of modifier-keywords is incorrect\"),\n    LOCAL_VARIABLE_EARLY_DECLARATION(false, \"3.10.2\", \"local variables should be declared close to the line where they are first used\"),\n    STRING_TEMPLATE_CURLY_BRACES(true, \"3.15.2\", \"string template has redundant curly braces\"),\n    STRING_TEMPLATE_QUOTES(true, \"3.15.2\", \"string template has redundant quotes\"),\n    FILE_NAME_MATCH_CLASS(true, \"3.1.2\", \"file name is incorrect - it should match with the class described in it if there is the only one class declared\"),\n    COLLAPSE_IF_STATEMENTS(true, \"3.16.1\", \"avoid using redundant nested if-statements, which could be collapsed into a single one\"),\n    CONVENTIONAL_RANGE(true, \"3.17.1\", \"use conventional rule for range case\"),\n    DEBUG_PRINT(false, \"3.18.1\", \"use a dedicated logging library\"),\n\n    // ======== chapter 4 ========\n    NULLABLE_PROPERTY_TYPE(true, \"4.3.1\", \"try to avoid use of nullable types\"),\n    TYPE_ALIAS(false, \"4.2.2\", \"variable's type is too complex and should be replaced with typealias\"),\n    SMART_CAST_NEEDED(true, \"4.2.1\", \"you can omit explicit casting\"),\n    SAY_NO_TO_VAR(false, \"4.1.3\", \"Usage of a mutable variables with [var] modifier - is a bad style, use [val] instead\"),\n    GENERIC_VARIABLE_WRONG_DECLARATION(true, \"4.3.2\", \"variable should have explicit type declaration\"),\n\n    // FixMe: change float literal to BigDecimal? Or kotlin equivalent?\n    FLOAT_IN_ACCURATE_CALCULATIONS(false, \"4.1.1\", \"floating-point values shouldn't be used in accurate calculations\"),\n    AVOID_NULL_CHECKS(true, \"4.3.3\", \"Try to avoid explicit null-checks\"),\n\n    // ======== chapter 5 ========\n    TOO_LONG_FUNCTION(false, \"5.1.1\", \"function is too long: split it or make more primitive\"),\n    AVOID_NESTED_FUNCTIONS(true, \"5.1.3\", \"try to avoid using nested functions\"),\n    LAMBDA_IS_NOT_LAST_PARAMETER(false, \"5.2.1\", \"lambda inside function parameters should be in the end\"),\n    TOO_MANY_PARAMETERS(false, \"5.2.2\", \"function has too many parameters\"),\n    NESTED_BLOCK(false, \"5.1.2\", \"function has too many nested blocks and should be simplified\"),\n    WRONG_OVERLOADING_FUNCTION_ARGUMENTS(false, \"5.2.3\", \"use default argument instead of function overloading\"),\n    RUN_BLOCKING_INSIDE_ASYNC(false, \"5.2.4\", \"avoid using runBlocking in asynchronous code\"),\n    TOO_MANY_LINES_IN_LAMBDA(false, \"5.2.5\", \"long lambdas should have a parameter name instead of it\"),\n    CUSTOM_LABEL(false, \"5.2.6\", \"avoid using expression with custom label\"),\n    PARAMETER_NAME_IN_OUTER_LAMBDA(false, \"5.2.7\", \"outer lambdas should have a parameter name instead of `it`\"),\n    INVERSE_FUNCTION_PREFERRED(true, \"5.1.4\", \"it is better to use inverse function\"),\n\n    // ======== chapter 6 ========\n    SINGLE_CONSTRUCTOR_SHOULD_BE_PRIMARY(true, \"6.1.1\", \"if a class has single constructor, it should be converted to a primary constructor\"),\n    USE_DATA_CLASS(false, \"6.1.2\", \"this class can be converted to a data class\"),\n    WRONG_NAME_OF_VARIABLE_INSIDE_ACCESSOR(false, \"6.1.9\", \"use `field` keyword instead of property name inside property accessors\"),\n    MULTIPLE_INIT_BLOCKS(true, \"6.1.4\", \"avoid using multiple `init` blocks, this logic can be moved to constructors or properties declarations\"),\n    CLASS_SHOULD_NOT_BE_ABSTRACT(true, \"6.1.6\", \"class should not be abstract, because it has no abstract functions\"),\n    CUSTOM_GETTERS_SETTERS(false, \"6.1.8\", \"custom getters and setters are not recommended, use class methods instead\"),\n    COMPACT_OBJECT_INITIALIZATION(true, \"6.1.11\", \"class instance can be initialized in `apply` block\"),\n    USELESS_SUPERTYPE(true, \"6.1.5\", \"unnecessary supertype specification\"),\n    TRIVIAL_ACCESSORS_ARE_NOT_RECOMMENDED(true, \"6.1.10\", \"trivial property accessors are not recommended\"),\n    EXTENSION_FUNCTION_SAME_SIGNATURE(false, \"6.2.2\", \"extension functions should not have same signature if their receiver classes are related\"),\n    EMPTY_PRIMARY_CONSTRUCTOR(true, \"6.1.3\", \"avoid empty primary constructor\"),\n    NO_CORRESPONDING_PROPERTY(false, \"6.1.7\", \"backing property should have the same name, but there is no corresponding property\"),\n    AVOID_USING_UTILITY_CLASS(false, \"6.4.1\", \"avoid using utility classes/objects, use extension functions instead\"),\n    OBJECT_IS_PREFERRED(true, \"6.4.2\", \"it is better to use object for stateless classes\"),\n    INLINE_CLASS_CAN_BE_USED(true, \"6.1.12\", \"inline class can be used\"),\n    EXTENSION_FUNCTION_WITH_CLASS(false, \"6.2.3\", \"do not use extension functions for the class defined in the same file\"),\n    RUN_IN_SCRIPT(true, \"6.5.1\", \"wrap blocks of code in top-level scope functions like `run`\"),\n    USE_LAST_INDEX(true, \"6.2.4\", \"Instead of \\\"length - 1\\\" need to use built-in \\\"lastIndex\\\" operation\"),\n    ;\n\n    /**\n     * Name of the inspection, it is used in configuration and in output.\n     */\n    override fun ruleName() = this.name\n\n    /**\n     * Warning message that will be logged to analysis report\n     */\n    fun warnText() = \"[${ruleName()}] ${this.warn}:\"\n\n    /**\n     * @param configRules list of [RulesConfig]\n     * @param emit function that will be called on warning\n     * @param freeText text that will be added to the warning message\n     * @param offset offset from the beginning of the file\n     * @param node the [ASTNode] on which the warning was triggered\n     * @param shouldBeAutoCorrected should be auto corrected or not\n     * @param isFixMode whether autocorrect mode is on\n     * @param autoFix function that will be called to autocorrect the warning\n     */\n    @Suppress(\"LongParameterList\", \"TOO_MANY_PARAMETERS\")\n    fun warnOnlyOrWarnAndFix(\n        configRules: List<RulesConfig>,\n        emit: DiktatErrorEmitter,\n        freeText: String,\n        offset: Int,\n        node: ASTNode,\n        shouldBeAutoCorrected: Boolean,\n        isFixMode: Boolean,\n        autoFix: () -> Unit,\n    ) {\n        if (shouldBeAutoCorrected) {\n            warnAndFix(configRules, emit, isFixMode, freeText, offset, node, autoFix)\n        } else {\n            warn(configRules, emit, freeText, offset, node)\n        }\n    }\n\n    /**\n     * @param configRules list of [RulesConfig]\n     * @param emit function that will be called on warning\n     * @param isFixMode whether autocorrect mode is on\n     * @param freeText text that will be added to the warning message\n     * @param offset offset from the beginning of the file\n     * @param node the [ASTNode] on which the warning was triggered\n     * @param autoFix function that will be called to autocorrect the warning\n     */\n    @Suppress(\"LongParameterList\", \"TOO_MANY_PARAMETERS\")\n    fun warnAndFix(\n        configRules: List<RulesConfig>,\n        emit: DiktatErrorEmitter,\n        isFixMode: Boolean,\n        freeText: String,\n        offset: Int,\n        node: ASTNode,\n        autoFix: () -> Unit,\n    ) {\n        require(canBeAutoCorrected) {\n            \"warnAndFix is called, but canBeAutoCorrected is false\"\n        }\n        doWarn(configRules, emit, freeText, offset, node, true)\n        fix(configRules, isFixMode, node, autoFix)\n    }\n\n    /**\n     * @param configs list of [RulesConfig]\n     * @param emit function that will be called on warning\n     * @param freeText text that will be added to the warning message\n     * @param offset offset from the beginning of the file\n     * @param node the [ASTNode] on which the warning was triggered\n     */\n    @Suppress(\"LongParameterList\", \"TOO_MANY_PARAMETERS\")\n    fun warn(\n        configs: List<RulesConfig>,\n        emit: DiktatErrorEmitter,\n        freeText: String,\n        offset: Int,\n        node: ASTNode,\n    ) {\n        doWarn(configs, emit, freeText, offset, node, false)\n    }\n\n    @Suppress(\"LongParameterList\", \"TOO_MANY_PARAMETERS\")\n    private fun doWarn(\n        configs: List<RulesConfig>,\n        emit: DiktatErrorEmitter,\n        freeText: String,\n        offset: Int,\n        node: ASTNode,\n        canBeAutoCorrected: Boolean,\n    ) {\n        if (isRuleFromActiveChapter(configs) && configs.isRuleEnabled(this) && !node.isSuppressed(name, this, configs)) {\n            val trimmedFreeText = freeText\n                .lines()\n                .run { if (size > 1) \"${first()}...\" else first() }\n            emit(\n                offset,\n                errorMessage = \"${this.warnText()} $trimmedFreeText\",\n                canBeAutoCorrected = canBeAutoCorrected,\n            )\n        }\n    }\n\n    private inline fun fix(\n        configs: List<RulesConfig>,\n        isFix: Boolean,\n        node: ASTNode,\n        autoFix: () -> Unit) {\n        if (isRuleFromActiveChapter(configs) && configs.isRuleEnabled(this) && isFix && !node.isSuppressed(name, this, configs)) {\n            autoFix()\n        }\n    }\n\n    companion object {\n        val names by lazy {\n            entries.map { it.name }\n        }\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/main/kotlin/com/saveourtool/diktat/ruleset/rules/DiktatRule.kt",
    "content": "package com.saveourtool.diktat.ruleset.rules\n\nimport com.saveourtool.diktat.api.DiktatErrorEmitter\nimport com.saveourtool.diktat.api.DiktatRuleNameAware\nimport com.saveourtool.diktat.api.isRuleEnabled\nimport com.saveourtool.diktat.common.config.rules.RulesConfig\nimport com.saveourtool.diktat.ruleset.utils.getFilePathSafely\n\nimport io.github.oshai.kotlinlogging.KotlinLogging\nimport org.jetbrains.kotlin.com.intellij.lang.ASTNode\n\nprivate typealias DiktatRuleApi = com.saveourtool.diktat.api.DiktatRule\n\n/**\n * This is a wrapper around _KtLint_ `com.pinterest.ktlint.core.Rule`.\n *\n * @param inspections warnings that are used in the rule's code\n * @property id id of the rule\n * @property configRules all rules from configuration\n */\n@Suppress(\"TooGenericExceptionCaught\")\nabstract class DiktatRule(\n    override val id: String,\n    val configRules: List<RulesConfig>,\n    private val inspections: List<DiktatRuleNameAware>,\n) : DiktatRuleApi {\n    /**\n     * Default value is false\n     */\n    var isFixMode: Boolean = false\n\n    /**\n     * The **file-specific** error emitter, initialized in\n     * [invoke] and used in [logic] implementations.\n     *\n     * Since the file is indirectly a part of the state of a `Rule`, the same\n     * `Rule` instance should **never be re-used** to check more than a single\n     * file, or confusing effects (incl. race conditions) will occur.\n     * See the documentation of the [com.pinterest.ktlint.core.Rule] class for more details.\n     *\n     * @see com.pinterest.ktlint.core.Rule\n     * @see invoke\n     * @see logic\n     */\n    lateinit var emitWarn: DiktatErrorEmitter\n\n    /**\n     * @param node\n     * @param autoCorrect\n     * @param emitter\n     * @throws Error\n     */\n    @Suppress(\"TooGenericExceptionThrown\")\n    override fun invoke(\n        node: ASTNode,\n        autoCorrect: Boolean,\n        emitter: DiktatErrorEmitter\n    ) {\n        emitWarn = emitter\n        isFixMode = autoCorrect\n\n        if (areInspectionsDisabled()) {\n            return\n        } else {\n            try {\n                logic(node)\n            } catch (internalError: Throwable) {\n                log.error(\n                    internalError\n                ) {\n                    \"\"\"Internal error has occurred in rule [$id]. Please make an issue on this bug at https://github.com/saveourtool/diKTat/.\n                       As a workaround you can disable these inspections in yml config: <$inspections>.\n                       Root cause of the problem is in [${node.getFilePathSafely()}] file.\n                    \"\"\".trimIndent()\n                }\n                // we are very sorry for throwing common Error here, but unfortunately we are not able to throw\n                // any existing Exception, as they will be caught in ktlint framework and the logging will be confusing:\n                // in this case it will incorrectly ask you to report issues in diktat to ktlint repository\n                throw Error(\"Internal error in diktat application\", internalError)\n            }\n        }\n    }\n\n    private fun areInspectionsDisabled(): Boolean =\n        inspections.none { configRules.isRuleEnabled(it) }\n\n    /**\n     * Logic of the rule\n     *\n     * @param node node that are coming from visit\n     */\n    abstract fun logic(node: ASTNode)\n\n    companion object {\n        private val log = KotlinLogging.logger {}\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/main/kotlin/com/saveourtool/diktat/ruleset/rules/DiktatRuleSetFactoryImpl.kt",
    "content": "package com.saveourtool.diktat.ruleset.rules\n\nimport com.saveourtool.diktat.api.DiktatRuleConfig\nimport com.saveourtool.diktat.api.DiktatRuleSet\nimport com.saveourtool.diktat.api.DiktatRuleSetFactory\nimport com.saveourtool.diktat.ruleset.rules.chapter1.FileNaming\nimport com.saveourtool.diktat.ruleset.rules.chapter1.IdentifierNaming\nimport com.saveourtool.diktat.ruleset.rules.chapter1.PackageNaming\nimport com.saveourtool.diktat.ruleset.rules.chapter2.comments.CommentsRule\nimport com.saveourtool.diktat.ruleset.rules.chapter2.comments.HeaderCommentRule\nimport com.saveourtool.diktat.ruleset.rules.chapter2.kdoc.CommentsFormatting\nimport com.saveourtool.diktat.ruleset.rules.chapter2.kdoc.KdocComments\nimport com.saveourtool.diktat.ruleset.rules.chapter2.kdoc.KdocFormatting\nimport com.saveourtool.diktat.ruleset.rules.chapter2.kdoc.KdocMethods\nimport com.saveourtool.diktat.ruleset.rules.chapter3.AnnotationNewLineRule\nimport com.saveourtool.diktat.ruleset.rules.chapter3.BlockStructureBraces\nimport com.saveourtool.diktat.ruleset.rules.chapter3.BooleanExpressionsRule\nimport com.saveourtool.diktat.ruleset.rules.chapter3.BracesInConditionalsAndLoopsRule\nimport com.saveourtool.diktat.ruleset.rules.chapter3.ClassLikeStructuresOrderRule\nimport com.saveourtool.diktat.ruleset.rules.chapter3.CollapseIfStatementsRule\nimport com.saveourtool.diktat.ruleset.rules.chapter3.ConsecutiveSpacesRule\nimport com.saveourtool.diktat.ruleset.rules.chapter3.DebugPrintRule\nimport com.saveourtool.diktat.ruleset.rules.chapter3.EmptyBlock\nimport com.saveourtool.diktat.ruleset.rules.chapter3.EnumsSeparated\nimport com.saveourtool.diktat.ruleset.rules.chapter3.LineLength\nimport com.saveourtool.diktat.ruleset.rules.chapter3.LongNumericalValuesSeparatedRule\nimport com.saveourtool.diktat.ruleset.rules.chapter3.MagicNumberRule\nimport com.saveourtool.diktat.ruleset.rules.chapter3.MultipleModifiersSequence\nimport com.saveourtool.diktat.ruleset.rules.chapter3.NullableTypeRule\nimport com.saveourtool.diktat.ruleset.rules.chapter3.PreviewAnnotationRule\nimport com.saveourtool.diktat.ruleset.rules.chapter3.RangeConventionalRule\nimport com.saveourtool.diktat.ruleset.rules.chapter3.SingleLineStatementsRule\nimport com.saveourtool.diktat.ruleset.rules.chapter3.SortRule\nimport com.saveourtool.diktat.ruleset.rules.chapter3.StringConcatenationRule\nimport com.saveourtool.diktat.ruleset.rules.chapter3.StringTemplateFormatRule\nimport com.saveourtool.diktat.ruleset.rules.chapter3.TrailingCommaRule\nimport com.saveourtool.diktat.ruleset.rules.chapter3.WhenMustHaveElseRule\nimport com.saveourtool.diktat.ruleset.rules.chapter3.files.BlankLinesRule\nimport com.saveourtool.diktat.ruleset.rules.chapter3.files.FileSize\nimport com.saveourtool.diktat.ruleset.rules.chapter3.files.FileStructureRule\nimport com.saveourtool.diktat.ruleset.rules.chapter3.files.IndentationRule\nimport com.saveourtool.diktat.ruleset.rules.chapter3.files.NewlinesRule\nimport com.saveourtool.diktat.ruleset.rules.chapter3.files.SemicolonsRule\nimport com.saveourtool.diktat.ruleset.rules.chapter3.files.TopLevelOrderRule\nimport com.saveourtool.diktat.ruleset.rules.chapter3.files.WhiteSpaceRule\nimport com.saveourtool.diktat.ruleset.rules.chapter3.identifiers.LocalVariablesRule\nimport com.saveourtool.diktat.ruleset.rules.chapter4.ImmutableValNoVarRule\nimport com.saveourtool.diktat.ruleset.rules.chapter4.NullChecksRule\nimport com.saveourtool.diktat.ruleset.rules.chapter4.SmartCastRule\nimport com.saveourtool.diktat.ruleset.rules.chapter4.TypeAliasRule\nimport com.saveourtool.diktat.ruleset.rules.chapter4.VariableGenericTypeDeclarationRule\nimport com.saveourtool.diktat.ruleset.rules.chapter4.calculations.AccurateCalculationsRule\nimport com.saveourtool.diktat.ruleset.rules.chapter5.AsyncAndSyncRule\nimport com.saveourtool.diktat.ruleset.rules.chapter5.AvoidNestedFunctionsRule\nimport com.saveourtool.diktat.ruleset.rules.chapter5.CheckInverseMethodRule\nimport com.saveourtool.diktat.ruleset.rules.chapter5.CustomLabel\nimport com.saveourtool.diktat.ruleset.rules.chapter5.FunctionArgumentsSize\nimport com.saveourtool.diktat.ruleset.rules.chapter5.FunctionLength\nimport com.saveourtool.diktat.ruleset.rules.chapter5.LambdaLengthRule\nimport com.saveourtool.diktat.ruleset.rules.chapter5.LambdaParameterOrder\nimport com.saveourtool.diktat.ruleset.rules.chapter5.NestedFunctionBlock\nimport com.saveourtool.diktat.ruleset.rules.chapter5.OverloadingArgumentsFunction\nimport com.saveourtool.diktat.ruleset.rules.chapter5.ParameterNameInOuterLambdaRule\nimport com.saveourtool.diktat.ruleset.rules.chapter6.AvoidEmptyPrimaryConstructor\nimport com.saveourtool.diktat.ruleset.rules.chapter6.AvoidUtilityClass\nimport com.saveourtool.diktat.ruleset.rules.chapter6.CustomGetterSetterRule\nimport com.saveourtool.diktat.ruleset.rules.chapter6.ExtensionFunctionsInFileRule\nimport com.saveourtool.diktat.ruleset.rules.chapter6.ExtensionFunctionsSameNameRule\nimport com.saveourtool.diktat.ruleset.rules.chapter6.ImplicitBackingPropertyRule\nimport com.saveourtool.diktat.ruleset.rules.chapter6.PropertyAccessorFields\nimport com.saveourtool.diktat.ruleset.rules.chapter6.RunInScript\nimport com.saveourtool.diktat.ruleset.rules.chapter6.TrivialPropertyAccessors\nimport com.saveourtool.diktat.ruleset.rules.chapter6.UseLastIndex\nimport com.saveourtool.diktat.ruleset.rules.chapter6.UselessSupertype\nimport com.saveourtool.diktat.ruleset.rules.chapter6.classes.AbstractClassesRule\nimport com.saveourtool.diktat.ruleset.rules.chapter6.classes.CompactInitialization\nimport com.saveourtool.diktat.ruleset.rules.chapter6.classes.DataClassesRule\nimport com.saveourtool.diktat.ruleset.rules.chapter6.classes.InlineClassesRule\nimport com.saveourtool.diktat.ruleset.rules.chapter6.classes.SingleConstructorRule\nimport com.saveourtool.diktat.ruleset.rules.chapter6.classes.SingleInitRule\nimport com.saveourtool.diktat.ruleset.rules.chapter6.classes.StatelessClassesRule\n\n/**\n * _KtLint_-agnostic factory which creates a [DiktatRuleSet].\n *\n * By default, it is expected to have `diktat-analysis.yml` configuration in the root folder where 'ktlint' is run\n * otherwise it will use default configuration where some rules are disabled.\n */\nclass DiktatRuleSetFactoryImpl : DiktatRuleSetFactory {\n    /**\n     * This method is going to be called once for each file (which means if any\n     * of the rules have state or are not thread-safe - a new [DiktatRuleSet] must\n     * be created).\n     *\n     * For each invocation of [com.pinterest.ktlint.core.KtLintRuleEngine.lint] and [com.pinterest.ktlint.core.KtLintRuleEngine.format] the [DiktatRuleSet]\n     * is retrieved.\n     * This results in new instances of each [com.pinterest.ktlint.core.Rule] for each file being\n     * processed.\n     * As of that a [com.pinterest.ktlint.core.Rule] does not need to be thread-safe.\n     *\n     * However, [com.pinterest.ktlint.core.KtLintRuleEngine.format] requires the [com.pinterest.ktlint.core.Rule] to be executed twice on a\n     * file in case at least one violation has been autocorrected.\n     * As the same [Rule] instance is reused for the second execution of the\n     * [Rule], the state of the [Rule] is shared.\n     * As of this [Rule] have to clear their internal state.\n     *\n     * @return a default [DiktatRuleSet]\n     */\n    @Suppress(\n        \"LongMethod\",\n        \"TOO_LONG_FUNCTION\",\n    )\n    override fun invoke(rulesConfig: List<DiktatRuleConfig>): DiktatRuleSet {\n        // Note: the order of rules is important in autocorrect mode. For example, all rules that add new code should be invoked before rules that fix formatting.\n        // We don't have a way to enforce a specific order, so we should just be careful when adding new rules to this list and, when possible,\n        // cover new rules in smoke test as well. If a rule needs to be at a specific position in a list, please add comment explaining it (like for NewlinesRule).\n        val rules = sequenceOf(\n            // semicolons, comments, documentation\n            ::SemicolonsRule,\n            ::CommentsRule,\n            ::SingleConstructorRule,  // this rule can add properties to a primary constructor, so should be before KdocComments\n            ::KdocComments,\n            ::KdocMethods,\n            ::KdocFormatting,\n            ::CommentsFormatting,\n            // naming\n            ::FileNaming,\n            ::PackageNaming,\n            ::IdentifierNaming,\n            // code structure\n            ::UselessSupertype,\n            ::ClassLikeStructuresOrderRule,\n            ::WhenMustHaveElseRule,\n            ::BracesInConditionalsAndLoopsRule,\n            ::EmptyBlock,\n            ::AvoidEmptyPrimaryConstructor,\n            ::TopLevelOrderRule,\n            ::SingleLineStatementsRule,\n            ::MultipleModifiersSequence,\n            ::TrivialPropertyAccessors,\n            ::CustomGetterSetterRule,\n            ::CompactInitialization,\n            // other rules\n            ::UseLastIndex,\n            ::InlineClassesRule,\n            ::ExtensionFunctionsInFileRule,\n            ::CheckInverseMethodRule,\n            ::StatelessClassesRule,\n            ::ImplicitBackingPropertyRule,\n            ::DataClassesRule,\n            ::LocalVariablesRule,\n            ::SmartCastRule,\n            ::AvoidUtilityClass,\n            ::PropertyAccessorFields,\n            ::AbstractClassesRule,\n            ::TrailingCommaRule,\n            ::SingleInitRule,\n            ::RangeConventionalRule,\n            ::DebugPrintRule,\n            ::CustomLabel,\n            ::VariableGenericTypeDeclarationRule,\n            ::LongNumericalValuesSeparatedRule,\n            ::NestedFunctionBlock,\n            ::AnnotationNewLineRule,\n            ::PreviewAnnotationRule,\n            ::SortRule,\n            ::EnumsSeparated,\n            ::StringConcatenationRule,\n            ::StringTemplateFormatRule,\n            ::AccurateCalculationsRule,\n            ::CollapseIfStatementsRule,\n            ::LineLength,\n            ::RunInScript,\n            ::TypeAliasRule,\n            ::OverloadingArgumentsFunction,\n            ::FunctionLength,\n            ::MagicNumberRule,\n            ::LambdaParameterOrder,\n            ::FunctionArgumentsSize,\n            ::BlankLinesRule,\n            ::FileSize,\n            ::AsyncAndSyncRule,\n            ::NullableTypeRule,\n            ::NullChecksRule,\n            ::ImmutableValNoVarRule,\n            ::AvoidNestedFunctionsRule,\n            ::ExtensionFunctionsSameNameRule,\n            ::LambdaLengthRule,\n            ::BooleanExpressionsRule,\n            ::ParameterNameInOuterLambdaRule,\n            // formatting: moving blocks, adding line breaks, indentations etc.\n            ::BlockStructureBraces,\n            ::ConsecutiveSpacesRule,\n            ::HeaderCommentRule,\n            ::FileStructureRule,  // this rule should be right before indentation because it should operate on already valid code\n            ::NewlinesRule,  // newlines need to be inserted right before fixing indentation\n            ::WhiteSpaceRule,  // this rule should be after other rules that can cause wrong spacing\n            ::IndentationRule,  // indentation rule should be the last because it fixes formatting after all the changes done by previous rules\n\n        )\n            .map {\n                it(rulesConfig)\n            }\n            .toList()\n        return DiktatRuleSet(rules)\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/main/kotlin/com/saveourtool/diktat/ruleset/rules/chapter1/FileNaming.kt",
    "content": "package com.saveourtool.diktat.ruleset.rules.chapter1\n\nimport com.saveourtool.diktat.common.config.rules.RulesConfig\nimport com.saveourtool.diktat.ruleset.constants.Warnings.FILE_NAME_INCORRECT\nimport com.saveourtool.diktat.ruleset.constants.Warnings.FILE_NAME_MATCH_CLASS\nimport com.saveourtool.diktat.ruleset.rules.DiktatRule\nimport com.saveourtool.diktat.ruleset.utils.getAllChildrenWithType\nimport com.saveourtool.diktat.ruleset.utils.getFilePath\nimport com.saveourtool.diktat.ruleset.utils.getFirstChildWithType\nimport com.saveourtool.diktat.ruleset.utils.isPascalCase\nimport com.saveourtool.diktat.util.isKotlinScript\n\nimport org.jetbrains.kotlin.KtNodeTypes.CLASS\nimport org.jetbrains.kotlin.com.intellij.lang.ASTNode\nimport org.jetbrains.kotlin.lexer.KtTokens.IDENTIFIER\nimport org.jetbrains.kotlin.psi.stubs.elements.KtFileElementType\n\nimport java.io.File\n\n/**\n * This visitor covers rule 1.2 of Huawei code style. It covers following rules related to a file naming:\n * 1) File must have \".kt\" extension\n * 2) File must be in camel case\n * 3) File name must start with capital letter (PascalCase)\n *\n * Aggressive: In case file contains only one class on upper level - it should be named with the same name\n */\n@Suppress(\"ForbiddenComment\")\nclass FileNaming(configRules: List<RulesConfig>) : DiktatRule(\n    NAME_ID,\n    configRules,\n    listOf(FILE_NAME_INCORRECT, FILE_NAME_MATCH_CLASS)\n) {\n    private lateinit var filePath: String\n\n    override fun logic(node: ASTNode) {\n        if (node.elementType == KtFileElementType.INSTANCE) {\n            filePath = node.getFilePath()\n            if (!filePath.isKotlinScript()) {\n                checkFileNaming(node)\n                checkClassNameMatchesWithFile(node)\n            }\n        }\n    }\n\n    private fun checkFileNaming(node: ASTNode) {\n        val (name, extension) = getFileParts(filePath)\n        if (!name.isPascalCase() || !validExtensions.contains(extension)) {\n            // FixMe: we can add an autocorrect here in future, but is there any purpose to change file or class name?\n            FILE_NAME_INCORRECT.warn(configRules, emitWarn, \"$name$extension\", 0, node)\n        }\n    }\n\n    @Suppress(\"UnsafeCallOnNullableType\", \"ControlFlowWithEmptyBody\")\n    private fun checkClassNameMatchesWithFile(fileLevelNode: ASTNode) {\n        val (fileNameWithoutSuffix, fileNameSuffix) = getFileParts(filePath)\n        val classes = fileLevelNode.getAllChildrenWithType(CLASS)\n        if (classes.size == 1) {\n            val className = classes[0].getFirstChildWithType(IDENTIFIER)!!.text\n            if (className != fileNameWithoutSuffix) {\n                // FixMe: we can add an autocorrect here in future, but is there any purpose to change file name?\n                FILE_NAME_MATCH_CLASS.warn(configRules, emitWarn, \"$fileNameWithoutSuffix$fileNameSuffix vs $className\", 0, fileLevelNode)\n            }\n        } else {\n            // FixMe: need to check that if there are several classes - at least one of them should match\n        }\n    }\n\n    private fun getFileParts(fileName: String): Pair<String, String> {\n        val file = File(fileName)\n        val fileNameWithoutSuffix = file.name.replace(Regex(\"\\\\..*\"), \"\")\n        val fileNameSuffix = file.name.replace(fileNameWithoutSuffix, \"\")\n        return Pair(fileNameWithoutSuffix, fileNameSuffix)\n    }\n\n    companion object {\n        // FixMe: should be moved to properties\n        const val NAME_ID = \"file-naming\"\n        val validExtensions = listOf(\".kt\", \".kts\")\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/main/kotlin/com/saveourtool/diktat/ruleset/rules/chapter1/IdentifierNaming.kt",
    "content": "@file:Suppress(\"FILE_WILDCARD_IMPORTS\")\n\npackage com.saveourtool.diktat.ruleset.rules.chapter1\n\nimport com.saveourtool.diktat.common.config.rules.RuleConfiguration\nimport com.saveourtool.diktat.common.config.rules.RulesConfig\nimport com.saveourtool.diktat.common.config.rules.getRuleConfig\nimport com.saveourtool.diktat.ruleset.constants.Warnings.BACKTICKS_PROHIBITED\nimport com.saveourtool.diktat.ruleset.constants.Warnings.CLASS_NAME_INCORRECT\nimport com.saveourtool.diktat.ruleset.constants.Warnings.CONFUSING_IDENTIFIER_NAMING\nimport com.saveourtool.diktat.ruleset.constants.Warnings.CONSTANT_UPPERCASE\nimport com.saveourtool.diktat.ruleset.constants.Warnings.ENUM_VALUE\nimport com.saveourtool.diktat.ruleset.constants.Warnings.EXCEPTION_SUFFIX\nimport com.saveourtool.diktat.ruleset.constants.Warnings.FUNCTION_BOOLEAN_PREFIX\nimport com.saveourtool.diktat.ruleset.constants.Warnings.FUNCTION_NAME_INCORRECT_CASE\nimport com.saveourtool.diktat.ruleset.constants.Warnings.GENERIC_NAME\nimport com.saveourtool.diktat.ruleset.constants.Warnings.IDENTIFIER_LENGTH\nimport com.saveourtool.diktat.ruleset.constants.Warnings.OBJECT_NAME_INCORRECT\nimport com.saveourtool.diktat.ruleset.constants.Warnings.TYPEALIAS_NAME_INCORRECT_CASE\nimport com.saveourtool.diktat.ruleset.constants.Warnings.VARIABLE_HAS_PREFIX\nimport com.saveourtool.diktat.ruleset.constants.Warnings.VARIABLE_NAME_INCORRECT\nimport com.saveourtool.diktat.ruleset.constants.Warnings.VARIABLE_NAME_INCORRECT_FORMAT\nimport com.saveourtool.diktat.ruleset.rules.DiktatRule\nimport com.saveourtool.diktat.ruleset.utils.*\nimport com.saveourtool.diktat.ruleset.utils.search.findAllVariablesWithUsages\n\nimport org.jetbrains.kotlin.KtNodeTypes\nimport org.jetbrains.kotlin.KtNodeTypes.CATCH\nimport org.jetbrains.kotlin.KtNodeTypes.CLASS\nimport org.jetbrains.kotlin.KtNodeTypes.DESTRUCTURING_DECLARATION\nimport org.jetbrains.kotlin.KtNodeTypes.DESTRUCTURING_DECLARATION_ENTRY\nimport org.jetbrains.kotlin.KtNodeTypes.FUNCTION_TYPE\nimport org.jetbrains.kotlin.KtNodeTypes.OBJECT_DECLARATION\nimport org.jetbrains.kotlin.KtNodeTypes.PROPERTY\nimport org.jetbrains.kotlin.KtNodeTypes.REFERENCE_EXPRESSION\nimport org.jetbrains.kotlin.KtNodeTypes.TYPE_PARAMETER\nimport org.jetbrains.kotlin.KtNodeTypes.TYPE_REFERENCE\nimport org.jetbrains.kotlin.KtNodeTypes.VALUE_PARAMETER_LIST\nimport org.jetbrains.kotlin.com.intellij.lang.ASTNode\nimport org.jetbrains.kotlin.com.intellij.psi.impl.source.tree.LeafPsiElement\nimport org.jetbrains.kotlin.com.intellij.psi.tree.TokenSet\nimport org.jetbrains.kotlin.kdoc.lexer.KDocTokens.KDOC\nimport org.jetbrains.kotlin.kdoc.parser.KDocKnownTag\nimport org.jetbrains.kotlin.lexer.KtTokens\nimport org.jetbrains.kotlin.lexer.KtTokens.CATCH_KEYWORD\nimport org.jetbrains.kotlin.lexer.KtTokens.IDENTIFIER\nimport org.jetbrains.kotlin.psi.KtParameter\nimport org.jetbrains.kotlin.psi.KtPrimaryConstructor\nimport org.jetbrains.kotlin.psi.KtProperty\nimport org.jetbrains.kotlin.psi.psiUtil.getParentOfType\nimport org.jetbrains.kotlin.psi.psiUtil.isPrivate\nimport org.jetbrains.kotlin.psi.psiUtil.parents\nimport org.jetbrains.kotlin.psi.stubs.elements.KtFileElementType\n\nimport java.util.Locale\n\n/**\n * This visitor covers rules:  1.2, 1.3, 1.4, 1.5 of Huawei code style. It covers following rules:\n * 1) All identifiers should use only ASCII letters or digits, and the names should match regular expressions \\w{2,64}\n *  exceptions: variables like i,j,k\n * 2) constants from companion object should have UPPER_SNAKE_CASE\n * 3) fields/variables should have lowerCamelCase and should not contain prefixes\n * 4) interfaces/classes/annotations/enums/object names should be in PascalCase\n * 5) methods: function names should be in camel case, methods that return boolean value should have \"is\"/\"has\" prefix\n * 6) custom exceptions: PascalCase and Exception suffix\n * 7) FixMe: should prohibit identifiers with free format with `` (except test functions)\n *\n * // FixMe: very important, that current implementation cannot fix identifier naming properly,\n * // FixMe: because it fixes only declaration without the usages\n */\n@Suppress(\"ForbiddenComment\", \"MISSING_KDOC_CLASS_ELEMENTS\")\nclass IdentifierNaming(configRules: List<RulesConfig>) : DiktatRule(\n    NAME_ID,\n    configRules,\n    listOf(BACKTICKS_PROHIBITED, VARIABLE_NAME_INCORRECT, VARIABLE_NAME_INCORRECT_FORMAT, CONSTANT_UPPERCASE,\n        VARIABLE_HAS_PREFIX, CONFUSING_IDENTIFIER_NAMING, GENERIC_NAME, CLASS_NAME_INCORRECT,\n        ENUM_VALUE, EXCEPTION_SUFFIX, FUNCTION_BOOLEAN_PREFIX, FUNCTION_NAME_INCORRECT_CASE,\n        IDENTIFIER_LENGTH, OBJECT_NAME_INCORRECT, TYPEALIAS_NAME_INCORRECT_CASE)\n) {\n    private val allMethodPrefixes by lazy {\n        if (configuration.allowedBooleanPrefixes.isEmpty()) {\n            booleanMethodPrefixes\n        } else {\n            booleanMethodPrefixes + configuration.allowedBooleanPrefixes.filter { it.isNotEmpty() }\n        }\n    }\n    val configuration by lazy {\n        BooleanFunctionsConfiguration(\n            this.configRules.getRuleConfig(FUNCTION_BOOLEAN_PREFIX)?.configuration ?: emptyMap()\n        )\n    }\n\n    override fun logic(\n        node: ASTNode\n    ) {\n        // backticks are prohibited for identifier declarations everywhere except test methods that are marked with @Test annotation\n        if (isIdentifierWithBackticks(node)) {\n            return\n        }\n\n        // isVariable is used as a workaround to check corner case with variables that have length == 1\n        val (identifierNodes, isVariable) = when (node.elementType) {\n            // covers interface, class, enum class and annotation class names\n            KtNodeTypes.CLASS -> Pair(checkClassNamings(node), false)\n            // covers \"object\" code blocks\n            KtNodeTypes.OBJECT_DECLARATION -> Pair(checkObjectNaming(node), false)\n            // covers variables (val/var), constants (const val) and parameters for lambdas\n            KtNodeTypes.PROPERTY, KtNodeTypes.VALUE_PARAMETER -> Pair(checkVariableName(node), true)\n            // covers case of enum values\n            KtNodeTypes.ENUM_ENTRY -> Pair(checkEnumValues(node), false)\n            // covers global functions, extensions and class methods\n            KtNodeTypes.FUN -> Pair(checkFunctionName(node), false)\n            // covers case of typeAlias values\n            KtNodeTypes.TYPEALIAS -> Pair(checkTypeAliases(node), false)\n            else -> Pair(null, false)\n        }\n\n        identifierNodes?.let {\n            checkIdentifierLength(it, isVariable)\n        }\n    }\n\n    /**\n     * method checks that identifier is wrapped over with backticks (``)\n     */\n    private fun isIdentifierWithBackticks(node: ASTNode): Boolean {\n        val identifier = node.getIdentifierName()\n        if (identifier != null && node.elementType != REFERENCE_EXPRESSION) {\n            // node is a symbol declaration with present identifier\n            val identifierText = identifier.text\n            if (identifierText.startsWith('`') && identifierText.endsWith('`')) {\n                val isTestFun = node.elementType == KtNodeTypes.FUN && node.hasTestAnnotation()\n                if (!isTestFun) {\n                    BACKTICKS_PROHIBITED.warn(configRules, emitWarn, identifierText, identifier.startOffset, identifier)\n                }\n                return true\n            }\n        }\n\n        return false\n    }\n\n    /**\n     * all checks for case and naming for vals/vars/constants\n     */\n    @Suppress(\n        \"SAY_NO_TO_VAR\",\n        \"TOO_LONG_FUNCTION\",\n        \"LongMethod\",\n        \"ComplexMethod\",\n        \"UnsafeCallOnNullableType\",\n    )\n\n    private fun checkVariableName(node: ASTNode): List<ASTNode> {\n        val configuration = ConstantUpperCaseConfiguration(\n            configRules.getRuleConfig(CONSTANT_UPPERCASE)?.configuration\n                ?: emptyMap())\n\n        val exceptionNames = configuration.exceptionConstNames\n\n        // special case for Destructuring declarations that can be treated as parameters in lambda:\n        var namesOfVariables = extractVariableIdentifiers(node)\n\n        // Only local private properties will be autofix in order not to break code if there are usages in other files.\n        // Destructuring declarations are only allowed for local variables/values, so we don't need to calculate `isFix` for every node in `namesOfVariables`\n        val isPublicOrNonLocalProperty = if (node.elementType == KtNodeTypes.PROPERTY) (node.psi as KtProperty).run { !isLocal && !isPrivate() } else false\n        val isNonPrivatePrimaryConstructorParameter = (node.psi as? KtParameter)?.run {\n            hasValOrVar() && getParentOfType<KtPrimaryConstructor>(true)?.valueParameters?.contains(this) == true && !isPrivate()\n        } ?: false\n        val shouldBeAutoCorrected = !(isPublicOrNonLocalProperty || isNonPrivatePrimaryConstructorParameter)\n        namesOfVariables\n            .forEach { variableName ->\n                // variable should not contain only one letter in it's name. This is a bad example: b512\n                // but no need to raise a warning here if length of a variable. In this case we will raise IDENTIFIER_LENGTH\n                if (variableName.text.containsOneLetterOrZero() && variableName.text.length > 1) {\n                    VARIABLE_NAME_INCORRECT.warn(configRules, emitWarn, variableName.text, variableName.startOffset, node)\n                }\n                // check if identifier of a property has a confusing name\n                if (confusingIdentifierNames.contains(variableName.text) && !isValidCatchIdentifier(variableName) &&\n                        node.elementType == KtNodeTypes.PROPERTY\n                ) {\n                    warnConfusingName(variableName)\n                }\n                // check for constant variables - check for val from companion object or on global file level\n                // it should be in UPPER_CASE, no need to raise this warning if it is one-letter variable\n                if (node.isConstant()) {\n                    if (!exceptionNames.contains(variableName.text) && !variableName.text.isUpperSnakeCase() && variableName.text.length > 1) {\n                        CONSTANT_UPPERCASE.warnOnlyOrWarnAndFix(\n                            configRules = configRules,\n                            emit = emitWarn,\n                            freeText = variableName.text,\n                            offset = variableName.startOffset,\n                            node = node,\n                            shouldBeAutoCorrected = shouldBeAutoCorrected,\n                            isFixMode = isFixMode,\n                        ) {\n                            (variableName as LeafPsiElement).rawReplaceWithText(variableName.text.toDeterministic { toUpperSnakeCase() })\n                        }\n                    }\n                } else if (variableName.text != \"_\" && !variableName.text.isLowerCamelCase() &&\n                        // variable name should be in camel case. The only exception is a list of industry standard variables like i, j, k.\n                        !isPairPropertyBackingField(null, node.psi as? KtProperty)\n                ) {\n                    VARIABLE_NAME_INCORRECT_FORMAT.warnOnlyOrWarnAndFix(\n                        configRules = configRules,\n                        emit = emitWarn,\n                        freeText = variableName.text,\n                        offset = variableName.startOffset,\n                        node = node,\n                        shouldBeAutoCorrected = shouldBeAutoCorrected,\n                        isFixMode = isFixMode,\n                    ) {\n                        // FixMe: cover fixes with tests\n                        val correctVariableName = variableName.text.toDeterministic { toLowerCamelCase() }\n                        variableName\n                            .parent { it.elementType == KtFileElementType.INSTANCE }\n                            ?.findAllVariablesWithUsages { it.name == variableName.text }\n                            ?.flatMap { it.value.toList() }\n                            ?.forEach { (it.node.firstChildNode as LeafPsiElement).rawReplaceWithText(correctVariableName) }\n                        if (variableName.treeParent.psi.run {\n                            (this is KtProperty && isMember) ||\n                                    (this is KtParameter && getParentOfType<KtPrimaryConstructor>(true)?.valueParameters?.contains(this) == true)\n                        }) {\n                            // For class members also check `@property` KDoc tag.\n                            // If we are here, then `variableName` is definitely a node from a class or an object.\n                            (variableName.parent(CLASS) ?: variableName.parent(OBJECT_DECLARATION))?.findChildByType(KDOC)?.kDocTags()\n                                ?.firstOrNull {\n                                    it.knownTag == KDocKnownTag.PROPERTY && it.getSubjectName() == variableName.text\n                                }\n                                ?.run {\n                                    (getSubjectLink()!!.node.findAllDescendantsWithSpecificType(IDENTIFIER).single() as LeafPsiElement).rawReplaceWithText(correctVariableName)\n                                }\n                        }\n                        (variableName as LeafPsiElement).rawReplaceWithText(correctVariableName)\n                    }\n                }\n            }\n\n        // need to get new node in case we have already converted the case before (and replaced the child node)\n        // we need to recalculate it twice, because nodes could have been changed by \"rawReplaceWithText\" function\n        namesOfVariables = extractVariableIdentifiers(node)\n        namesOfVariables\n            .forEach { variableName ->\n                // generally, variables with prefixes are not allowed (like mVariable, xCode, iValue)\n                if (variableName.text.hasPrefix()) {\n                    VARIABLE_HAS_PREFIX.warnAndFix(configRules, emitWarn, isFixMode, variableName.text, variableName.startOffset, node) {\n                        (variableName as LeafPsiElement).rawReplaceWithText(variableName.text.removePrefix())\n                    }\n                }\n            }\n        return namesOfVariables\n    }\n\n    /**\n     * Warns that variable have a confusing name\n     */\n    private fun warnConfusingName(variableName: ASTNode) {\n        val warnText = when (variableName.text) {\n            \"O\", \"D\" -> \"better name is: obj, dgt\"\n            \"I\", \"l\" -> \"better name is: it, ln, line\"\n            \"Z\" -> \"better name is: n1, n2\"\n            \"S\" -> \"better name is: xs, str\"\n            \"e\" -> \"better name is: ex, elm\"\n            \"B\" -> \"better name is: bt, nxt\"\n            \"h\", \"n\" -> \"better name is: nr, head, height\"\n            \"m\", \"rn\" -> \"better name is: mbr, item\"\n            else -> \"\"\n\n        }\n        CONFUSING_IDENTIFIER_NAMING.warn(configRules, emitWarn, warnText, variableName.startOffset, variableName)\n    }\n\n    /**\n     * Getting identifiers (aka variable names) from parent nodes like PROPERTY.\n     * Several things to take into account here:\n     *     * need to handle DESTRUCTURING_DECLARATION correctly, as it does not have IDENTIFIER leaf.\n     *     * function type can have VALUE_PARAMETERs without name\n     */\n    @Suppress(\"UnsafeCallOnNullableType\")\n    private fun extractVariableIdentifiers(node: ASTNode): List<ASTNode> {\n        val destructingDeclaration = node.getFirstChildWithType(DESTRUCTURING_DECLARATION)\n        val result = if (destructingDeclaration != null) {\n            destructingDeclaration.getAllChildrenWithType(DESTRUCTURING_DECLARATION_ENTRY)\n                .map { it.getIdentifierName()!! }\n        } else if (node.parents().count() > 1 && node.treeParent.elementType == VALUE_PARAMETER_LIST &&\n                node.treeParent.treeParent.elementType == FUNCTION_TYPE\n        ) {\n            listOfNotNull(node.getIdentifierName())\n        } else {\n            listOf(node.getIdentifierName()!!)\n        }\n\n        // no need to do checks if variables are in a special list with exceptions\n        return result.filterNot { oneCharIdentifiers.contains(it.text) }\n    }\n\n    /**\n     * basic check for class naming (PascalCase)\n     * and checks for generic type declared for this class\n     */\n    private fun checkClassNamings(node: ASTNode): List<ASTNode> {\n        val genericType: ASTNode? = node.getTypeParameterList()\n        if (genericType != null && !validGenericTypeName(genericType)) {\n            // FixMe: should fix generic name here\n            GENERIC_NAME.warn(configRules, emitWarn, genericType.text, genericType.startOffset, genericType)\n        }\n\n        val className: ASTNode = node.getIdentifierName() ?: return emptyList()\n        if (!(className.text.isPascalCase())) {\n            CLASS_NAME_INCORRECT.warnAndFix(configRules, emitWarn, isFixMode, className.text, className.startOffset, className) {\n                (className as LeafPsiElement).rawReplaceWithText(className.text.toDeterministic { toPascalCase() })\n            }\n        }\n\n        checkExceptionSuffix(node)\n        return listOf(className)\n    }\n\n    /**\n     * all exceptions should have Exception suffix\n     *\n     */\n    private fun checkExceptionSuffix(node: ASTNode) {\n        val classNameNode = node.getIdentifierName() ?: return\n        // getting super class name\n        val superClassName: String? = node\n            .getFirstChildWithType(KtNodeTypes.SUPER_TYPE_LIST)\n            ?.findLeafWithSpecificType(TYPE_REFERENCE)\n            ?.text\n\n        if (superClassName != null && hasExceptionSuffix(superClassName) && !hasExceptionSuffix(classNameNode.text)) {\n            EXCEPTION_SUFFIX.warnAndFix(configRules, emitWarn, isFixMode, classNameNode.text, classNameNode.startOffset, classNameNode) {\n                // FixMe: need to add tests for this\n                (classNameNode as LeafPsiElement).rawReplaceWithText(classNameNode.text + \"Exception\")\n            }\n        }\n    }\n\n    private fun hasExceptionSuffix(text: String) = text.lowercase(Locale.getDefault()).endsWith(\"exception\")\n\n    /**\n     * basic check for object naming of code blocks (PascalCase)\n     * fix: fixing object name to PascalCase\n     */\n    private fun checkObjectNaming(node: ASTNode): List<ASTNode> {\n        // if this object is companion object or anonymous object - it does not have any name\n        val objectName: ASTNode = node.getIdentifierName() ?: return emptyList()\n        if (!objectName.text.isPascalCase()) {\n            OBJECT_NAME_INCORRECT.warnAndFix(configRules, emitWarn, isFixMode, objectName.text, objectName.startOffset, objectName) {\n                (objectName as LeafPsiElement).rawReplaceWithText(objectName.text.toDeterministic { toPascalCase() })\n            }\n        }\n        return listOf(objectName)\n    }\n\n    /**\n     * check that Enum values match correct case and style\n     * node has ENUM_ENTRY type\n     * to check all variables will need to check all IDENTIFIERS in ENUM_ENTRY\n     */\n    private fun checkEnumValues(node: ASTNode): List<ASTNode> {\n        val enumValues: List<ASTNode> = node.getChildren(null).filter { it.elementType == KtTokens.IDENTIFIER }\n        enumValues.forEach { value ->\n            val configuration = IdentifierNamingConfiguration(\n                configRules.getRuleConfig(ENUM_VALUE)?.configuration\n                    ?: emptyMap()\n            )\n            val validator = when (configuration.enumStyle) {\n                Style.PASCAL_CASE -> String::isPascalCase\n                Style.SNAKE_CASE -> String::isUpperSnakeCase\n            }\n            val autofix = when (configuration.enumStyle) {\n                Style.PASCAL_CASE -> String::toPascalCase\n                Style.SNAKE_CASE -> String::toUpperSnakeCase\n            }\n            if (!validator(value.text)) {\n                ENUM_VALUE.warnAndFix(\n                    configRules,\n                    emitWarn,\n                    isFixMode,\n                    \"${value.text} (should be in ${configuration.enumStyle.str})\",\n                    value.startOffset, value\n                ) {\n                    // FixMe: add tests for this\n                    (value as LeafPsiElement).rawReplaceWithText(autofix(value.text))\n                }\n            }\n\n            if (confusingIdentifierNames.contains(value.text)) {\n                warnConfusingName(value)\n            }\n        }\n\n        return enumValues\n    }\n\n    /**\n     * Check function name:\n     * 1) function names should be in camel case\n     * 2) methods that return boolean value should have \"is\"/\"has\" prefix\n     * 3) FixMe: The function name is usually a verb or verb phrase (need to add check/fix for it)\n     * 4) backticks are prohibited in the naming of non-test methods\n     */\n    @Suppress(\"UnsafeCallOnNullableType\")\n    private fun checkFunctionName(node: ASTNode): List<ASTNode>? {\n        val functionName = node.getIdentifierName() ?: return null\n\n        // basic check for camel case\n        if (!functionName.text.isLowerCamelCase()) {\n            FUNCTION_NAME_INCORRECT_CASE.warnAndFix(configRules, emitWarn, isFixMode, functionName.text, functionName.startOffset, functionName) {\n                // FixMe: add tests for this\n                (functionName as LeafPsiElement).rawReplaceWithText(functionName.text.toDeterministic { toLowerCamelCase() })\n            }\n        }\n\n        // We don't need to ask subclasses to rename superclass methods\n        if (!node.isOverridden()) {\n            // check for methods that return Boolean\n            // if function has Boolean return type in 99% of cases it is much better to name it with isXXX or hasXXX prefix\n            @Suppress(\"COLLAPSE_IF_STATEMENTS\")\n\n            if (node.hasBooleanReturnType() && !node.isOperatorFun() && allMethodPrefixes.none { functionName.text.startsWith(it) }) {\n                // FixMe: add agressive autofix for this\n                FUNCTION_BOOLEAN_PREFIX.warn(configRules, emitWarn, functionName.text, functionName.startOffset, functionName)\n            }\n        }\n\n        return listOf(functionName)\n    }\n\n    @Suppress(\"UnsafeCallOnNullableType\")\n    private fun checkTypeAliases(node: ASTNode): List<ASTNode> {\n        val aliasName = node.getIdentifierName()!!\n\n        if (!aliasName.text.isPascalCase()) {\n            TYPEALIAS_NAME_INCORRECT_CASE.warnAndFix(configRules, emitWarn, isFixMode, aliasName.text, aliasName.startOffset, aliasName) {\n                (aliasName as LeafPsiElement).rawReplaceWithText(aliasName.text.toDeterministic { toPascalCase() })\n            }\n        }\n        return listOf(aliasName)\n    }\n\n    /**\n     * check that generic name has single capital letter, can be followed by a number\n     * this method will check it for both generic classes and generic methods\n     */\n    private fun validGenericTypeName(generic: ASTNode) = generic.getChildren(TokenSet.create(TYPE_PARAMETER)).all {\n        val typeText = it.getIdentifierName()?.text ?: return false\n        // first letter should always be a capital and other letters - are digits\n        typeText[0] in 'A'..'Z' && (typeText.length == 1 || typeText.substring(1).isDigits())\n    }\n\n    /**\n     * identifier name length should not be longer than 64 symbols and shorter than 2 symbols\n     */\n    private fun checkIdentifierLength(\n        nodes: List<ASTNode>,\n        isVariable: Boolean\n    ) {\n        nodes.forEach {\n            val isValidOneCharVariable = oneCharIdentifiers.contains(it.text) && isVariable\n            if (it.text != \"_\" && !it.isTextLengthInRange(MIN_IDENTIFIER_LENGTH..MAX_IDENTIFIER_LENGTH) &&\n                    !isValidOneCharVariable && !isValidCatchIdentifier(it)\n            ) {\n                IDENTIFIER_LENGTH.warn(configRules, emitWarn, it.text, it.startOffset, it)\n            }\n        }\n    }\n\n    /**\n     * exception case for identifiers used in catch block:\n     * catch (e: Exception) {}\n     */\n    private fun isValidCatchIdentifier(node: ASTNode): Boolean {\n        val parentValueParamList = node.findParentNodeWithSpecificType(VALUE_PARAMETER_LIST)\n        val prevCatchKeyWord = parentValueParamList?.prevCodeSibling()?.elementType == CATCH_KEYWORD\n        return node.text == \"e\" && node.findParentNodeWithSpecificType(CATCH) != null && prevCatchKeyWord\n    }\n\n    /**\n     * [RuleConfiguration] for identifier naming\n     */\n    class IdentifierNamingConfiguration(config: Map<String, String>) : RuleConfiguration(config) {\n        @Suppress(\"CUSTOM_GETTERS_SETTERS\")\n        private val Style.isEnumStyle: Boolean\n            get() = listOf(Style.PASCAL_CASE, Style.SNAKE_CASE).contains(this)\n\n        /**\n         * In which style enum members should be named\n         */\n        val enumStyle = config[\"enumStyle\"]?.let { styleString ->\n            val style = Style.entries.firstOrNull {\n                it.name == styleString.toUpperSnakeCase()\n            }\n            if (style == null || !style.isEnumStyle) {\n                error(\"$styleString is unsupported for enum style\")\n            }\n            style\n        } ?: Style.SNAKE_CASE\n    }\n\n    class ConstantUpperCaseConfiguration(config: Map<String, String>) : RuleConfiguration(config) {\n        val exceptionConstNames = config[\"exceptionConstNames\"]?.split(',') ?: emptyList()\n    }\n\n    class BooleanFunctionsConfiguration(config: Map<String, String>) : RuleConfiguration(config) {\n        /**\n         * A list of functions that return boolean and are allowed to use. Input is in a form \"foo, bar\".\n         */\n        val allowedBooleanPrefixes = config[\"allowedPrefixes\"]?.split(\",\")?.map { it.trim() } ?: emptyList()\n    }\n\n    companion object {\n        private const val MAX_DETERMINISTIC_RUNS = 5\n        const val MAX_IDENTIFIER_LENGTH = 64\n        const val MIN_IDENTIFIER_LENGTH = 2\n        const val NAME_ID = \"identifier-naming\"\n\n        // FixMe: this should be moved to properties\n        val oneCharIdentifiers = setOf(\"i\", \"j\", \"k\", \"x\", \"y\", \"z\")\n        val booleanMethodPrefixes = setOf(\"has\", \"is\", \"are\", \"have\", \"should\", \"can\")\n        val confusingIdentifierNames = setOf(\"O\", \"D\", \"I\", \"l\", \"Z\", \"S\", \"e\", \"B\", \"h\", \"n\", \"m\", \"rn\")\n\n        private fun String.toDeterministic(function: String.() -> String): String = generateSequence(function(this), function)\n            .runningFold(this to false) { (current, result), next ->\n                require(!result) {\n                    \"Should return a value already\"\n                }\n                next to (current == next)\n            }\n            .take(MAX_DETERMINISTIC_RUNS)\n            .first { it.second }\n            .first\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/main/kotlin/com/saveourtool/diktat/ruleset/rules/chapter1/PackageNaming.kt",
    "content": "package com.saveourtool.diktat.ruleset.rules.chapter1\n\nimport com.saveourtool.diktat.common.config.rules.CommonConfiguration\nimport com.saveourtool.diktat.common.config.rules.RulesConfig\nimport com.saveourtool.diktat.common.config.rules.getCommonConfiguration\nimport com.saveourtool.diktat.ruleset.constants.Warnings.INCORRECT_PACKAGE_SEPARATOR\nimport com.saveourtool.diktat.ruleset.constants.Warnings.PACKAGE_NAME_INCORRECT_CASE\nimport com.saveourtool.diktat.ruleset.constants.Warnings.PACKAGE_NAME_INCORRECT_PATH\nimport com.saveourtool.diktat.ruleset.constants.Warnings.PACKAGE_NAME_INCORRECT_PREFIX\nimport com.saveourtool.diktat.ruleset.constants.Warnings.PACKAGE_NAME_INCORRECT_SYMBOLS\nimport com.saveourtool.diktat.ruleset.constants.Warnings.PACKAGE_NAME_MISSING\nimport com.saveourtool.diktat.ruleset.rules.DiktatRule\nimport com.saveourtool.diktat.ruleset.utils.*\nimport com.saveourtool.diktat.util.isKotlinScript\n\nimport io.github.oshai.kotlinlogging.KotlinLogging\nimport org.jetbrains.kotlin.KtNodeTypes.DOT_QUALIFIED_EXPRESSION\nimport org.jetbrains.kotlin.KtNodeTypes.FILE_ANNOTATION_LIST\nimport org.jetbrains.kotlin.KtNodeTypes.IMPORT_LIST\nimport org.jetbrains.kotlin.KtNodeTypes.PACKAGE_DIRECTIVE\nimport org.jetbrains.kotlin.KtNodeTypes.REFERENCE_EXPRESSION\nimport org.jetbrains.kotlin.com.intellij.lang.ASTFactory\nimport org.jetbrains.kotlin.com.intellij.lang.ASTNode\nimport org.jetbrains.kotlin.com.intellij.psi.impl.source.tree.LeafPsiElement\nimport org.jetbrains.kotlin.com.intellij.psi.impl.source.tree.PsiWhiteSpaceImpl\nimport org.jetbrains.kotlin.kdoc.lexer.KDocTokens.KDOC\nimport org.jetbrains.kotlin.konan.file.File\nimport org.jetbrains.kotlin.lexer.KtTokens.BLOCK_COMMENT\nimport org.jetbrains.kotlin.lexer.KtTokens.EOL_COMMENT\nimport org.jetbrains.kotlin.lexer.KtTokens.IDENTIFIER\nimport org.jetbrains.kotlin.lexer.KtTokens.PACKAGE_KEYWORD\nimport org.jetbrains.kotlin.lexer.KtTokens.WHITE_SPACE\nimport org.jetbrains.kotlin.psi.psiUtil.children\n\nimport java.util.concurrent.atomic.AtomicInteger\n\n/**\n * Rule 1.3: package name is in lower case and separated by dots, code developed internally in your company (in example Huawei) should start\n * with it's domain (like com.huawei), and the package name is allowed to have numbers\n *\n * Current limitations and FixMe:\n * need to support autofixing of directories in the same way as package is named. For example if we have package name:\n * package a.b.c.D -> then class D should be placed in a/b/c/ directories\n */\n@Suppress(\"ForbiddenComment\", \"TOO_MANY_LINES_IN_LAMBDA\")\nclass PackageNaming(configRules: List<RulesConfig>) : DiktatRule(\n    NAME_ID,\n    configRules,\n    listOf(INCORRECT_PACKAGE_SEPARATOR, PACKAGE_NAME_INCORRECT_CASE, PACKAGE_NAME_MISSING,\n        PACKAGE_NAME_INCORRECT_PATH, PACKAGE_NAME_INCORRECT_PREFIX, PACKAGE_NAME_INCORRECT_SYMBOLS),\n) {\n    private lateinit var domainName: String\n\n    override fun logic(node: ASTNode) {\n        val configuration = configRules.getCommonConfiguration()\n        configuration.domainName?.let {\n            domainName = it\n            if (node.elementType == PACKAGE_DIRECTIVE) {\n                val filePath = node.getFilePath()\n\n                // getting all identifiers from existing package name into the list like [org, diktat, project]\n                val wordsInPackageName = node.findAllDescendantsWithSpecificType(IDENTIFIER)\n\n                if (wordsInPackageName.isEmpty() && filePath.isKotlinScript()) {\n                    // kotlin scripts are allowed to have empty package; in this case we don't suggest a new one and don't run checks\n                    return\n                }\n\n                // calculating package name based on the directory where the file is placed\n                val realPackageName = calculateRealPackageName(filePath, configuration)\n\n                // if node isLeaf - this means that there is no package name declared\n                if (node.isLeaf() && !filePath.isKotlinScript()) {\n                    warnAndFixMissingPackageName(node, realPackageName, filePath)\n                    return\n                }\n\n                // no need to check that packageIdentifiers is empty, because in this case parsing will fail\n                checkPackageName(wordsInPackageName, node)\n                // fix in checkFilePathMatchesWithPackageName is much more aggressive than fixes in checkPackageName, they can conflict\n                checkFilePathMatchesWithPackageName(wordsInPackageName, realPackageName, node)\n            }\n        } ?: if (visitorCounter.incrementAndGet() == 1) {\n            log.error {\n                \"Not able to find an external configuration for domain\" +\n                        \" name in the common configuration (is it missing in yml config?)\"\n            }\n        } else {\n            @Suppress(\"RedundantUnitExpression\")\n            Unit\n        }\n    }\n\n    /**\n     * checking and fixing the case when package directive is missing in the file\n     */\n    private fun warnAndFixMissingPackageName(\n        initialPackageDirectiveNode: ASTNode,\n        realPackageName: List<String>,\n        filePath: String\n    ) {\n        val fileName = filePath.substringAfterLast(File.separator)\n\n        // if the file path contains \"buildSrc\" - don't add the package name to the file\n        val isBuildSrcPath = \"buildSrc\" in filePath\n\n        if (!isBuildSrcPath) {\n            PACKAGE_NAME_MISSING.warnAndFix(configRules, emitWarn, isFixMode, fileName,\n                initialPackageDirectiveNode.startOffset, initialPackageDirectiveNode) {\n                if (realPackageName.isNotEmpty()) {\n                    // creating node for package directive using Kotlin parser\n                    val newPackageDirectiveName = realPackageName.joinToString(PACKAGE_SEPARATOR)\n                    insertNewPackageName(initialPackageDirectiveNode, newPackageDirectiveName)\n                }\n            }\n        }\n    }\n\n    /**\n     * calculating real package name based on the directory path where the file is stored\n     *\n     * @return list with words that are parts of package name like [org, diktat, name]\n     */\n    private fun calculateRealPackageName(fileName: String, configuration: CommonConfiguration): List<String> {\n        val filePathParts = fileName\n            .splitPathToDirs()\n            .dropLast(1)  // remove filename\n            .flatMap { it.split(\".\") }\n\n        return if (!filePathParts.contains(PACKAGE_PATH_ANCHOR)) {\n            log.error {\n                \"Not able to determine a path to a scanned file or \\\"$PACKAGE_PATH_ANCHOR\\\" directory cannot be found in it's path.\" +\n                        \" Will not be able to determine correct package name. It can happen due to missing <$PACKAGE_PATH_ANCHOR> directory in the path\"\n            }\n            emptyList()\n        } else {\n            // creating a real package name:\n            // 1) getting a path after the base project directory (after \"src\" directory)\n            // 2) removing src/main/kotlin/java/e.t.c dirs\n            // 3) adding company's domain name at the beginning\n            val allDirs = languageDirNames + configuration.srcDirectories + configuration.testAnchors\n            val fileSubDir = filePathParts.subList(filePathParts.lastIndexOf(PACKAGE_PATH_ANCHOR), filePathParts.size)\n                .dropWhile { allDirs.contains(it) }\n            // no need to add DOMAIN_NAME to the package name if it is already in path\n            val domainPrefix = if (!fileSubDir.joinToString(PACKAGE_SEPARATOR).startsWith(domainName)) domainName.split(PACKAGE_SEPARATOR) else emptyList()\n            domainPrefix + fileSubDir\n        }\n    }\n\n    private fun checkPackageName(wordsInPackageName: List<ASTNode>, packageDirectiveNode: ASTNode) {\n        // all words should be in a lower case (lower case letters/digits/underscore)\n        wordsInPackageName\n            .filter { word -> word.text.hasUppercaseLetter() }\n            .forEach { word ->\n                PACKAGE_NAME_INCORRECT_CASE.warnAndFix(configRules, emitWarn, isFixMode, word.text, word.startOffset, word) {\n                    word.toLower()\n                }\n            }\n\n        // package name should start from a company's domain name\n        if (!isDomainMatches(wordsInPackageName)) {\n            PACKAGE_NAME_INCORRECT_PREFIX.warnAndFix(configRules, emitWarn, isFixMode, domainName,\n                wordsInPackageName[0].startOffset, wordsInPackageName[0]) {\n                val oldPackageName = wordsInPackageName.joinToString(PACKAGE_SEPARATOR) { it.text }\n                val newPackageName = \"$domainName$PACKAGE_SEPARATOR$oldPackageName\"\n                insertNewPackageName(packageDirectiveNode, newPackageName)\n            }\n        }\n\n        // all words should contain only ASCII letters or digits\n        wordsInPackageName\n            .filter { word -> !areCorrectSymbolsUsed(word.text) }\n            .forEach { PACKAGE_NAME_INCORRECT_SYMBOLS.warn(configRules, emitWarn, it.text, it.startOffset, it) }\n\n        // all words should contain only ASCII letters or digits\n        wordsInPackageName.forEach { correctPackageWordSeparatorsUsed(it) }\n    }\n\n    /**\n     * only letters, digits and underscore are allowed\n     */\n    private fun areCorrectSymbolsUsed(word: String): Boolean {\n        // underscores are allowed in some cases - see \"exceptionForUnderscore\"\n        val wordFromPackage = word.replace(\"_\", \"\")\n        return wordFromPackage.isASCIILettersAndDigits()\n    }\n\n    /**\n     * in package name no other separators except dot should be used, package words (parts) should be concatenated\n     * without any symbols or should use dot symbol - this is the only way\n     */\n    private fun correctPackageWordSeparatorsUsed(word: ASTNode) {\n        if (word.text.contains(\"_\") && !isExceptionForUnderscore(word.text)) {\n            INCORRECT_PACKAGE_SEPARATOR.warnAndFix(configRules, emitWarn, isFixMode, word.text, word.startOffset, word) {\n                (word as LeafPsiElement).rawReplaceWithText(word.text.replace(\"_\", \"\"))\n            }\n        }\n    }\n\n    /** Underscores! In some cases, if the package name starts with a number or other characters,\n     * but these characters cannot be used at the beginning of the Java/Kotlin package name,\n     * or the package name contains reserved Java keywords, underscores are allowed.\n     * For example: org.example.hyphenated_name,int_.example, com.example._123name\n     */\n    private fun isExceptionForUnderscore(word: String): Boolean {\n        val wordFromPackage = word.replace(\"_\", \"\")\n\n        return wordFromPackage[0].isDigit() ||\n                wordFromPackage.isKotlinKeyWord() ||\n                wordFromPackage.isJavaKeyWord()\n    }\n\n    /**\n     * function simply checks that package name starts with a proper domain name\n     */\n    private fun isDomainMatches(packageNameParts: List<ASTNode>): Boolean {\n        val packageNamePrefix = domainName.split(PACKAGE_SEPARATOR)\n        if (packageNameParts.size < packageNamePrefix.size) {\n            return false\n        }\n\n        for (i in packageNamePrefix.indices) {\n            if (packageNameParts[i].text != packageNamePrefix[i]) {\n                return false\n            }\n        }\n        return true\n    }\n\n    @Suppress(\"UnsafeCallOnNullableType\")\n    private fun insertNewPackageName(packageDirectiveNode: ASTNode, packageName: String) {\n        // package name can be dot qualified expression or a reference expression in case it contains only one word\n        val packageNameNode = packageDirectiveNode.findChildByType(DOT_QUALIFIED_EXPRESSION)\n            ?: packageDirectiveNode.findChildByType(REFERENCE_EXPRESSION)\n\n        val generatedPackageDirective = KotlinParser()\n            .createNode(\"$PACKAGE_KEYWORD $packageName\", true)\n\n        packageNameNode?.let {\n            // simply replacing only node connected with the package name, all other nodes remain unchanged\n            packageDirectiveNode.replaceChild(packageNameNode,\n                generatedPackageDirective.findLeafWithSpecificType(DOT_QUALIFIED_EXPRESSION)!!)\n        }\n            ?: run {\n                // there is missing package statement in a file, so it will be created and inserted\n                val newPackageDirective = generatedPackageDirective.findLeafWithSpecificType(PACKAGE_DIRECTIVE)!!\n                val packageDirectiveParent = packageDirectiveNode.treeParent\n                // When package directive is missing in .kt file,\n                // the node is still present in the AST, and not always in a convenient place.\n                // E.g. `@file:Suppress(\"...\") // comments`\n                // AST will be: FILE_ANNOTATION_LIST, PACKAGE_DIRECTIVE, WHITE_SPACE, EOL_COMMENT\n                // So, we can't just put new package directive in it's old place and rely on FileStructure rule\n                if (packageDirectiveNode != packageDirectiveParent.firstChildNode) {\n                    // We will insert new package directive node before first node, which is not in the following list\n                    val possibleTypesBeforePackageDirective = listOf(WHITE_SPACE, EOL_COMMENT, BLOCK_COMMENT, KDOC, PACKAGE_DIRECTIVE, FILE_ANNOTATION_LIST)\n                    val addBefore = packageDirectiveParent.children().first { it.elementType !in possibleTypesBeforePackageDirective }\n                    packageDirectiveParent.removeChild(packageDirectiveNode)\n                    packageDirectiveParent.addChild(newPackageDirective, addBefore)\n                    if (newPackageDirective.treePrev.elementType != WHITE_SPACE) {\n                        packageDirectiveParent.addChild(PsiWhiteSpaceImpl(\"\\n\"), newPackageDirective)\n                    }\n                } else {\n                    packageDirectiveParent.replaceChild(packageDirectiveNode, newPackageDirective)\n                }\n                addWhiteSpaceIfRequired(newPackageDirective, packageDirectiveParent)\n            }\n    }\n\n    private fun addWhiteSpaceIfRequired(packageNode: ASTNode, packageParentNode: ASTNode) {\n        if (packageNode.treeNext.isWhiteSpace()) {\n            return\n        }\n        if (!packageNode.treeNext.isEmptyImportList()) {\n            packageParentNode.addChild(ASTFactory.whitespace(\"\\n\"), packageNode.treeNext)\n        } else {\n            // IMPORT_LIST without imports is after PACKAGE_NODE\n            // WHITE_SPACE needs to be after IMPORT_LIST only\n            packageParentNode.addChild(ASTFactory.whitespace(\"\\n\"), packageNode.treeNext.treeNext)\n        }\n    }\n\n    /**\n     * checking and fixing package directive if it does not match with the directory where the file is stored\n     */\n    private fun checkFilePathMatchesWithPackageName(packageNameParts: List<ASTNode>,\n                                                    realNameParts: List<String>,\n                                                    packageDirective: ASTNode\n    ) {\n        if (realNameParts.isNotEmpty() && packageNameParts.map { node -> node.text } != realNameParts) {\n            val realPackageNameStr = realNameParts.joinToString(PACKAGE_SEPARATOR)\n            val offset = packageNameParts[0].startOffset\n            PACKAGE_NAME_INCORRECT_PATH.warnAndFix(configRules, emitWarn, isFixMode,\n                realPackageNameStr, offset, packageNameParts[0]) {\n                insertNewPackageName(packageDirective, realPackageNameStr)\n            }\n        }\n    }\n\n    companion object {\n        private val log = KotlinLogging.logger {}\n        const val NAME_ID = \"package-naming\"\n\n        /**\n         * Directory which is considered the start of sources file tree\n         */\n        const val PACKAGE_PATH_ANCHOR = SRC_DIRECTORY_NAME\n\n        /**\n         * Symbol that is used to separate parts in package name\n         */\n        const val PACKAGE_SEPARATOR = \".\"\n\n        /**\n         * tricky hack (counter) that helps not to raise multiple warnings about the package name if config is missing\n         */\n        var visitorCounter = AtomicInteger(0)\n\n        /**\n         * Targets described in [KMM documentation](https://kotlinlang.org/docs/reference/mpp-supported-platforms.html)\n         */\n        private val kmmTargets = listOf(\"common\", \"jvm\", \"js\", \"android\", \"ios\", \"androidNativeArm32\", \"androidNativeArm64\", \"iosArm32\", \"iosArm64\", \"iosX64\",\n            \"watchosArm32\", \"watchosArm64\", \"watchosX86\", \"tvosArm64\", \"tvosX64\", \"macosX64\", \"linuxArm64\", \"linuxArm32Hfp\", \"linuxMips32\", \"linuxMipsel32\", \"linuxX64\",\n            \"mingwX64\", \"mingwX86\", \"wasm32\", \"macosArm64\")\n\n        /**\n         * Directories that are supposed to be first in sources file paths, relative to [PACKAGE_PATH_ANCHOR].\n         * For kotlin multiplatform projects directories for targets from [kmmTargets] are supported.\n         */\n        val languageDirNames = listOf(\"src\", \"java\", \"kotlin\") + kmmTargets.flatMap { listOf(\"${it}Main\", \"${it}Test\") }\n\n        private fun ASTNode.isEmptyImportList() = elementType == IMPORT_LIST && children().none()\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/main/kotlin/com/saveourtool/diktat/ruleset/rules/chapter2/comments/CommentsRule.kt",
    "content": "package com.saveourtool.diktat.ruleset.rules.chapter2.comments\n\nimport com.saveourtool.diktat.common.config.rules.RulesConfig\nimport com.saveourtool.diktat.ruleset.constants.Warnings.COMMENTED_OUT_CODE\nimport com.saveourtool.diktat.ruleset.rules.DiktatRule\nimport com.saveourtool.diktat.ruleset.utils.findAllDescendantsWithSpecificType\nimport com.saveourtool.diktat.ruleset.utils.getFilePath\nimport com.saveourtool.diktat.ruleset.utils.prevSibling\n\nimport io.github.oshai.kotlinlogging.KotlinLogging\nimport org.jetbrains.kotlin.com.intellij.lang.ASTNode\nimport org.jetbrains.kotlin.com.intellij.psi.TokenType\nimport org.jetbrains.kotlin.lexer.KtTokens\nimport org.jetbrains.kotlin.lexer.KtTokens.BLOCK_COMMENT\nimport org.jetbrains.kotlin.lexer.KtTokens.EOL_COMMENT\nimport org.jetbrains.kotlin.lexer.KtTokens.WHITE_SPACE\nimport org.jetbrains.kotlin.name.FqName\nimport org.jetbrains.kotlin.psi.KtPsiFactory\nimport org.jetbrains.kotlin.psi.stubs.elements.KtFileElementType\nimport org.jetbrains.kotlin.resolve.ImportPath\n\nprivate typealias ListOfPairs = MutableList<Pair<ASTNode, String>>\n\n/**\n * This rule performs checks if there is any commented code.\n * No commented out code is allowed, including imports.\n */\n@Suppress(\"ForbiddenComment\")\nclass CommentsRule(configRules: List<RulesConfig>) : DiktatRule(\n    NAME_ID,\n    configRules,\n    listOf(COMMENTED_OUT_CODE)\n) {\n    private lateinit var ktPsiFactory: KtPsiFactory\n\n    override fun logic(node: ASTNode) {\n        ktPsiFactory = KtPsiFactory(node.psi.project, false)  // regarding markGenerated see KDoc in Kotlin sources\n        if (node.elementType == KtFileElementType.INSTANCE) {\n            checkCommentedCode(node)\n        }\n    }\n\n    /**\n     * This method tries to detect commented code by uncommenting and parsing it. If parser reports errors,\n     * we assume this is not code (it is hard to try and parse further because comments can contain code snippets).\n     *\n     * @implNote\n     * 1. Import and package directives should be separated from the rest of uncommented lines\n     * 2. Import usually go on top of the file, so if comment contains not only imports, it probably contains imports only on top. (this possibly needs fixme)\n     * 3. Code can be surrounded by actual comments. One possible heuristic here is to assume actual comments start\n     *    with '// ' with whitespace, while automatic commenting in, e.g., IDEA creates slashes in the beginning of the line\n     *\n     */\n    @Suppress(\n        \"UnsafeCallOnNullableType\",\n        \"TOO_LONG_FUNCTION\",\n        \"AVOID_NULL_CHECKS\"\n    )\n    private fun checkCommentedCode(node: ASTNode) {\n        val errorNodesWithText: ListOfPairs = mutableListOf()\n        val eolCommentsOffsetToText = getOffsetsToTextBlocksFromEolComments(node, errorNodesWithText)\n        val blockCommentsOffsetToText = node\n            .findAllDescendantsWithSpecificType(BLOCK_COMMENT)\n            .map {\n                errorNodesWithText.add(it to it.text.trim().removeSurrounding(\"/*\", \"*/\"))\n                it.startOffset to it.text.trim().removeSurrounding(\"/*\", \"*/\")\n            }\n        (eolCommentsOffsetToText + blockCommentsOffsetToText)\n            .flatMap { (offset, text) ->\n                val (singleLines, blockLines) = text.lines().partition { it.contains(importOrPackage) }\n                val block = if (blockLines.isNotEmpty()) listOf(blockLines.joinToString(\"\\n\")) else emptyList()\n                (singleLines + block).map {\n                    offset to it\n                }\n            }\n            .map { (offset, text) -> offset to text.trim() }\n            .mapNotNull { (offset, text) ->\n                when {\n                    text.isPossibleImport() ->\n                        offset to ktPsiFactory.createImportDirective(ImportPath.fromString(text.substringAfter(importKeywordWithSpace, \"\"))).node\n                    text.trimStart().startsWith(packageKeywordWithSpace) ->\n                        offset to ktPsiFactory.createPackageDirective(FqName(text.substringAfter(packageKeywordWithSpace, \"\"))).node\n                    else -> if (isContainingRequiredPartOfCode(text)) {\n                        offset to ktPsiFactory.createBlockCodeFragment(text, null).node\n                    } else {\n                        null\n                    }\n                }\n            }\n            .filter { (_, parsedNode) ->\n                parsedNode\n                    .findAllDescendantsWithSpecificType(TokenType.ERROR_ELEMENT)\n                    .isEmpty()\n            }\n            .forEach { (offset, parsedNode) ->\n                val invalidNode = errorNodesWithText.find {\n                    it.second.trim().contains(parsedNode.text, false) ||\n                            parsedNode.text.contains(it.second.trim(), false)\n                }?.first\n                if (invalidNode == null) {\n                    logger.warn {\n                        \"Text [${parsedNode.text}] is a piece of code, created from comment; \" +\n                                \"but no matching text in comments has been found in the file ${node.getFilePath()}\"\n                    }\n                } else {\n                    COMMENTED_OUT_CODE.warn(\n                        configRules,\n                        emitWarn,\n                        parsedNode.text.substringBefore(\"\\n\").trim(),\n                        offset,\n                        invalidNode\n                    )\n                }\n            }\n    }\n\n    /**\n     * This method is used to extract text from EOL comments in a form which can be used for parsing.\n     * Multiple consecutive EOL comments can correspond to one code block, so we try to glue them together here.\n     * Splitting back into lines, if necessary, will be done outside of this method, for both text from EOL and block.\n     * fixme: in this case offset is lost for lines which will be split once more\n     */\n    private fun getOffsetsToTextBlocksFromEolComments(node: ASTNode, errorNodesWithText: ListOfPairs): List<Pair<Int, String>> {\n        val comments = node\n            .findAllDescendantsWithSpecificType(EOL_COMMENT)\n            .filter { !it.text.contains(eolCommentStart) || isCodeAfterCommentStart(it.text) }\n        return if (comments.isNotEmpty()) {\n            val result = mutableListOf(mutableListOf(comments.first()))\n            comments\n                .drop(1)\n                .fold(result) { acc, astNode ->\n                    val isImportOrPackage = astNode.text.contains(importOrPackage)\n                    val previousNonWhiteSpaceNode = astNode.prevSibling { it.elementType != WHITE_SPACE }\n                    if (!isImportOrPackage && previousNonWhiteSpaceNode in acc.last()) {\n                        acc.last().add(astNode)\n                    } else {\n                        acc.add(mutableListOf(astNode))\n                    }\n                    acc\n                }\n                .map { list ->\n                    list.forEach { errorNodesWithText.add(it to it.text.removePrefix(\"//\")) }\n                    list.first().startOffset to list.joinToString(\"\\n\") { it.text.removePrefix(\"//\") }\n                }\n        } else {\n            emptyList()\n        }\n    }\n\n    /**\n     * This is a very rare case. We should check this cases for 4 things:\n     *\n     * 1. If it is a class/object at the beginning of the line\n     * 2. If it is a function\n     * 3. If it is import/package implementation\n     * 4. If it is }. This case is used when } goes after one space and it is closing class or fun\n     */\n    private fun isCodeAfterCommentStart(text: String): Boolean {\n        val textWithoutCommentStartToken = text.removePrefix(\"//\").trim()\n        return codeFileStartCases.any { textWithoutCommentStartToken.contains(it) }\n    }\n\n    private fun isContainingRequiredPartOfCode(text: String): Boolean =\n        text.contains(\"val \", true) || text.contains(\"var \", true) || text.contains(\"=\", true) || (text.contains(\"{\", true) && text.substringAfter(\"{\").contains(\"}\", true))\n\n    /**\n     * Some weak checks to see if this string can be used as a part of import statement.\n     * Only string surrounded in backticks or a dot-qualified expression (i.e., containing words maybe separated by dots)\n     * are considered for this case.\n     */\n    private fun String.isPossibleImport(): Boolean = trimStart().startsWith(importKeywordWithSpace) &&\n            substringAfter(importKeywordWithSpace, \"\").run {\n                startsWith('`') && endsWith('`') || !contains(' ')\n            }\n\n    @Suppress(\"MaxLineLength\")\n    companion object {\n        const val NAME_ID = \"comments\"\n        private val logger = KotlinLogging.logger {}\n        private val importKeywordWithSpace = \"${KtTokens.IMPORT_KEYWORD.value} \"\n        private val packageKeywordWithSpace = \"${KtTokens.PACKAGE_KEYWORD.value} \"\n        private val importOrPackage = \"\"\"($importKeywordWithSpace|$packageKeywordWithSpace)\"\"\".toRegex()\n        private val classRegex =\n            \"\"\"^\\s*(public|private|protected)*\\s*(internal)*\\s*(open|data|sealed)*\\s*(internal)*\\s*(class|object)\\s+(\\w+)(\\(.*\\))*(\\s*:\\s*\\w+(\\(.*\\))*)?\\s*\\{*$\"\"\".toRegex()\n        private val importOrPackageRegex = \"\"\"^(import|package)?\\s+([a-zA-Z.])+;*$\"\"\".toRegex()\n        private val functionRegex = \"\"\"^(public|private|protected)*\\s*(override|abstract|actual|expect)*\\s?fun\\s+\\w+(\\(.*\\))?(\\s*:\\s*\\w+)?\\s*[{=]${'$'}\"\"\".toRegex()\n        private val rightBraceRegex = \"\"\"^\\s*}$\"\"\".toRegex()\n        private val valOrVarRegex = \"\"\"val |var \"\"\".toRegex()\n        private val codeFileStartCases = listOf(classRegex, importOrPackageRegex, functionRegex, rightBraceRegex, valOrVarRegex)\n        private val eolCommentStart = \"\"\"// \\S\"\"\".toRegex()\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/main/kotlin/com/saveourtool/diktat/ruleset/rules/chapter2/comments/HeaderCommentRule.kt",
    "content": "package com.saveourtool.diktat.ruleset.rules.chapter2.comments\n\nimport com.saveourtool.diktat.common.config.rules.RuleConfiguration\nimport com.saveourtool.diktat.common.config.rules.RulesConfig\nimport com.saveourtool.diktat.common.config.rules.getRuleConfig\nimport com.saveourtool.diktat.ruleset.constants.Warnings.HEADER_MISSING_IN_NON_SINGLE_CLASS_FILE\nimport com.saveourtool.diktat.ruleset.constants.Warnings.HEADER_MISSING_OR_WRONG_COPYRIGHT\nimport com.saveourtool.diktat.ruleset.constants.Warnings.HEADER_NOT_BEFORE_PACKAGE\nimport com.saveourtool.diktat.ruleset.constants.Warnings.HEADER_WRONG_FORMAT\nimport com.saveourtool.diktat.ruleset.constants.Warnings.WRONG_COPYRIGHT_YEAR\nimport com.saveourtool.diktat.ruleset.rules.DiktatRule\nimport com.saveourtool.diktat.ruleset.utils.copyrightWords\nimport com.saveourtool.diktat.ruleset.utils.findChildAfter\nimport com.saveourtool.diktat.ruleset.utils.findChildBefore\nimport com.saveourtool.diktat.ruleset.utils.getAllChildrenWithType\nimport com.saveourtool.diktat.ruleset.utils.getFilePath\nimport com.saveourtool.diktat.ruleset.utils.getFirstChildWithType\nimport com.saveourtool.diktat.ruleset.utils.isGradleScript\nimport com.saveourtool.diktat.ruleset.utils.isWhiteSpace\nimport com.saveourtool.diktat.ruleset.utils.moveChildBefore\n\nimport io.github.oshai.kotlinlogging.KotlinLogging\nimport org.jetbrains.kotlin.KtNodeTypes\nimport org.jetbrains.kotlin.KtNodeTypes.IMPORT_LIST\nimport org.jetbrains.kotlin.KtNodeTypes.PACKAGE_DIRECTIVE\nimport org.jetbrains.kotlin.com.intellij.lang.ASTNode\nimport org.jetbrains.kotlin.com.intellij.psi.impl.source.tree.LeafElement\nimport org.jetbrains.kotlin.com.intellij.psi.impl.source.tree.LeafPsiElement\nimport org.jetbrains.kotlin.com.intellij.psi.impl.source.tree.PsiWhiteSpaceImpl\nimport org.jetbrains.kotlin.kdoc.lexer.KDocTokens.KDOC\nimport org.jetbrains.kotlin.lexer.KtTokens\nimport org.jetbrains.kotlin.lexer.KtTokens.BLOCK_COMMENT\nimport org.jetbrains.kotlin.lexer.KtTokens.WHITE_SPACE\nimport org.jetbrains.kotlin.psi.stubs.elements.KtFileElementType\n\nimport java.time.LocalDate\n\n/**\n * Visitor for header comment in .kt file:\n * 1) Ensure header comment is at the very top and properly formatted (has newline after KDoc end)\n * 2) Ensure copyright exists and is properly formatted\n * 3) Ensure there are no dates or authors\n * 4) Ensure files with many or zero classes have proper description\n */\n@Suppress(\"ForbiddenComment\")\nclass HeaderCommentRule(configRules: List<RulesConfig>) : DiktatRule(\n    NAME_ID,\n    configRules,\n    listOf(HEADER_MISSING_IN_NON_SINGLE_CLASS_FILE, HEADER_MISSING_OR_WRONG_COPYRIGHT, HEADER_NOT_BEFORE_PACKAGE,\n        HEADER_NOT_BEFORE_PACKAGE, HEADER_WRONG_FORMAT, WRONG_COPYRIGHT_YEAR),\n) {\n    override fun logic(node: ASTNode) {\n        if (node.elementType == KtFileElementType.INSTANCE && !node.getFilePath().isGradleScript()) {\n            checkCopyright(node)\n            if (checkHeaderKdocPosition(node)) {\n                checkHeaderKdoc(node)\n            }\n        }\n    }\n\n    private fun checkHeaderKdoc(node: ASTNode) {\n        node.findChildBefore(PACKAGE_DIRECTIVE, KDOC)?.let { headerKdoc ->\n            if (headerKdoc.treeNext != null && headerKdoc.treeNext.elementType == WHITE_SPACE &&\n                    headerKdoc.treeNext.text.count { it == '\\n' } != 2) {\n                HEADER_WRONG_FORMAT.warnAndFix(configRules, emitWarn, isFixMode,\n                    \"header KDoc should have a new line after\", headerKdoc.startOffset, headerKdoc) {\n                    node.replaceChild(headerKdoc.treeNext, PsiWhiteSpaceImpl(\"\\n\\n\"))\n                }\n            }\n        }\n            ?: run {\n                val numDeclaredClassesAndObjects = node.getAllChildrenWithType(KtNodeTypes.CLASS).size +\n                        node.getAllChildrenWithType(KtNodeTypes.OBJECT_DECLARATION).size\n                if (numDeclaredClassesAndObjects != 1) {\n                    HEADER_MISSING_IN_NON_SINGLE_CLASS_FILE.warn(configRules, emitWarn,\n                        \"there are $numDeclaredClassesAndObjects declared classes and/or objects\", node.startOffset, node)\n                }\n            }\n    }\n\n    /**\n     * If corresponding rule is enabled, checks if header KDoc is positioned correctly and moves it in fix mode.\n     * Algorithm is as follows: if there is no KDoc at the top of file (before package directive) and the one after imports\n     * isn't bound to any identifier, than this KDoc is misplaced header KDoc.\n     *\n     * @return true if position check is not needed or if header KDoc is positioned correctly or it was moved by fix mode\n     */\n    @Suppress(\"FUNCTION_BOOLEAN_PREFIX\")\n    private fun checkHeaderKdocPosition(node: ASTNode): Boolean {\n        val firstKdoc = node.findChildAfter(IMPORT_LIST, KDOC)\n        // if `firstKdoc.treeParent` is File then it's a KDoc not bound to any other structures\n        if (node.findChildBefore(PACKAGE_DIRECTIVE, KDOC) == null && firstKdoc != null && firstKdoc.treeParent.elementType == KtFileElementType.INSTANCE) {\n            HEADER_NOT_BEFORE_PACKAGE.warnAndFix(configRules, emitWarn, isFixMode, \"header KDoc is located after package or imports\", firstKdoc.startOffset, firstKdoc) {\n                node.moveChildBefore(firstKdoc, node.getFirstChildWithType(PACKAGE_DIRECTIVE), true)\n                // ensure there is no empty line between copyright and header kdoc\n                node.findChildBefore(PACKAGE_DIRECTIVE, BLOCK_COMMENT)?.apply {\n                    if (treeNext.elementType == WHITE_SPACE) {\n                        node.replaceChild(treeNext, PsiWhiteSpaceImpl(\"\\n\"))\n                    } else {\n                        node.addChild(PsiWhiteSpaceImpl(\"\\n\"), this.treeNext)\n                    }\n                }\n            }\n            if (!isFixMode) {\n                return false\n            }\n        }\n        return true\n    }\n\n    private fun makeCopyrightCorrectYear(copyrightText: String): String {\n        val hyphenYear = hyphenRegex.find(copyrightText)\n\n        hyphenYear?.let {\n            val copyrightYears = hyphenYear.value.split(\"-\")\n            if (copyrightYears[1].toInt() != curYear) {\n                val validYears = \"${copyrightYears[0]}-$curYear\"\n                return copyrightText.replace(hyphenRegex, validYears)\n            }\n        }\n\n        val afterCopyrightYear = afterCopyrightRegex.find(copyrightText)\n        val copyrightYears = afterCopyrightYear?.value?.split(\"(c)\", \"(C)\", \"©\")\n        return if (copyrightYears != null && copyrightYears[1].trim().toInt() != curYear) {\n            val validYears = \"${copyrightYears[0]}-$curYear\"\n            copyrightText.replace(afterCopyrightRegex, validYears)\n        } else {\n            \"\"\n        }\n    }\n\n    @Suppress(\"TOO_LONG_FUNCTION\", \"ComplexMethod\")\n    private fun checkCopyright(node: ASTNode) {\n        val configuration = CopyrightConfiguration(configRules.getRuleConfig(HEADER_MISSING_OR_WRONG_COPYRIGHT)?.configuration\n            ?: emptyMap())\n        if (!configuration.isCopyrightMandatory() && !configuration.hasCopyrightText()) {\n            return\n        }\n\n        // need to make sure that copyright year is consistent with current year\n        val copyrightText = configuration.getCopyrightText()\n        val copyrightWithCorrectYear = makeCopyrightCorrectYear(copyrightText)\n\n        if (copyrightWithCorrectYear.isNotEmpty()) {\n            log.warn { \"Copyright year in your configuration file is not up to date.\" }\n        }\n\n        val headerComment = node.findChildBefore(PACKAGE_DIRECTIVE, BLOCK_COMMENT)\n        // Depends only on content and doesn't consider years\n        val isCopyrightMatchesPatternExceptFirstYear = isCopyRightTextMatchesPattern(headerComment, copyrightText) ||\n                isCopyRightTextMatchesPattern(headerComment, copyrightWithCorrectYear)\n\n        val isWrongCopyright = headerComment != null &&\n                !isCopyrightMatchesPatternExceptFirstYear &&\n                !isHeaderCommentContainText(headerComment, copyrightText) &&\n                !isHeaderCommentContainText(headerComment, copyrightWithCorrectYear)\n\n        val isMissingCopyright = headerComment == null && configuration.isCopyrightMandatory()\n        val isCopyrightInsideKdoc = (node.getAllChildrenWithType(KDOC) + node.getAllChildrenWithType(KtTokens.EOL_COMMENT))\n            .any { commentNode ->\n                copyrightWords.any { commentNode.text.contains(it, ignoreCase = true) }\n            }\n\n        if (isWrongCopyright || isMissingCopyright || isCopyrightInsideKdoc) {\n            val freeText = when {\n                // If `isCopyrightInsideKdoc` then `isMissingCopyright` is true too, but warning text from `isCopyrightInsideKdoc` is preferable.\n                isCopyrightInsideKdoc -> \"copyright is placed inside KDoc, but should be inside a block comment\"\n                isWrongCopyright -> \"copyright comment doesn't have correct copyright text\"\n                isMissingCopyright -> \"copyright is mandatory, but is missing\"\n                else -> error(\"Should never get to this point\")\n            }\n            HEADER_MISSING_OR_WRONG_COPYRIGHT.warnAndFix(configRules, emitWarn, isFixMode, freeText, node.startOffset, node) {\n                headerComment?.let { copyrightNode ->\n                    // remove node clearly, with trailing whitespace\n                    if (copyrightNode.treeNext.isWhiteSpace()) {\n                        node.removeChild(copyrightNode.treeNext)\n                    }\n                    node.removeChild(copyrightNode)\n                }\n                // do not insert empty line before header kdoc\n                val newLines = node.findChildBefore(PACKAGE_DIRECTIVE, KDOC)?.let { \"\\n\" } ?: \"\\n\\n\"\n                node.addChild(PsiWhiteSpaceImpl(newLines), node.firstChildNode)\n                node.addChild(LeafPsiElement(BLOCK_COMMENT,\n                    \"\"\"\n                        |/*\n                        |${handleMultilineCopyright(copyrightWithCorrectYear.ifEmpty { copyrightText })}\n                        |*/\n                    \"\"\".trimMargin()),\n                    node.firstChildNode\n                )\n            }\n        }\n\n        // Triggers when there is a copyright, but its year is not updated.\n        if (!isMissingCopyright && !isWrongCopyright && copyrightWithCorrectYear.isNotEmpty()) {\n            WRONG_COPYRIGHT_YEAR.warnAndFix(configRules, emitWarn, isFixMode, \"year should be $curYear\", node.startOffset, node) {\n                (headerComment as LeafElement).rawReplaceWithText(headerComment.text.replace(copyrightText, copyrightWithCorrectYear))\n            }\n        }\n    }\n\n    private fun isHeaderCommentContainText(headerComment: ASTNode, text: String): Boolean = if (text.isNotEmpty()) headerComment.text.flatten().contains(text.flatten()) else false\n\n    // Check if provided copyright node differs only in the first date from pattern\n    private fun isCopyRightTextMatchesPattern(copyrightNode: ASTNode?, copyrightPattern: String): Boolean {\n        val copyrightText = copyrightNode?.text\n            ?.replace(\"/*\", \"\")\n            ?.replace(\"*/\", \"\")\n            ?.replace(\"*\", \"\")\n\n        val datesInPattern = hyphenRegex.find(copyrightPattern)?.value\n        val datesInCode = copyrightText?.let { hyphenRegex.find(it)?.value }\n\n        if (datesInPattern == null || datesInCode == null) {\n            return false\n        }\n\n        val patternWithoutDates = copyrightPattern.replace(datesInPattern, \"\").flatten()\n        val textWithoutDates = copyrightText.replace(datesInCode, \"\").flatten()\n\n        // Text should be equal, first date could be different, second date should be equal to current year\n        return (patternWithoutDates == textWithoutDates) && (datesInCode.substringAfter(\"-\") == curYear.toString())\n    }\n\n    /**\n     * Deletes all spaces and newlines\n     * Used to compare copyrights in yaml and file\n     */\n    private fun String.flatten(): String =\n        replace(\"\\n\", \"\")\n            .replace(\" \", \"\")\n\n    /**\n     * If it is multiline copyright, this method deletes spaces in empty lines.\n     * Otherwise, if it is one line copyright, it returns it with 4 spaces at the beginning.\n     */\n    private fun handleMultilineCopyright(copyrightText: String): String {\n        if (copyrightText.startsWith(\" \")) {\n            return copyrightText\n                .lines()\n                .dropWhile { it.isBlank() }\n                .reduce { acc, nextLine ->\n                    when {\n                        nextLine.isBlank() -> \"$acc\\n\"\n                        else -> \"$acc\\n$nextLine\"\n                    }\n                }\n        }\n\n        return \"    $copyrightText\"\n    }\n\n    /**\n     * Configuration for copyright\n     */\n    class CopyrightConfiguration(config: Map<String, String>) : RuleConfiguration(config) {\n        /**\n         * @return Whether the copyright is mandatory in all files\n         */\n        fun isCopyrightMandatory() = config[\"isCopyrightMandatory\"]?.toBoolean() ?: false\n\n        /**\n         * Whether copyright text is present in the configuration\n         *\n         * @return true if config has \"copyrightText\"\n         */\n        internal fun hasCopyrightText() = config.keys.contains(\"copyrightText\")\n\n        /**\n         * @return text of copyright as configured in the configuration file\n         */\n        fun getCopyrightText() = config[\"copyrightText\"]?.replace(CURR_YEAR_PATTERN, curYear.toString())\n            ?: error(\"Copyright is not set in configuration\")\n    }\n\n    companion object {\n        private val log = KotlinLogging.logger {}\n        const val CURR_YEAR_PATTERN = \";@currYear;\"\n        const val NAME_ID = \"header-comment\"\n        val hyphenRegex = Regex(\"\"\"\\d+-\\d+\"\"\")\n        val afterCopyrightRegex = Regex(\"\"\"((©|\\([cC]\\))+ *\\d+)\"\"\")\n        val curYear = LocalDate.now().year\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/main/kotlin/com/saveourtool/diktat/ruleset/rules/chapter2/kdoc/CommentsFormatting.kt",
    "content": "package com.saveourtool.diktat.ruleset.rules.chapter2.kdoc\n\nimport com.saveourtool.diktat.common.config.rules.RuleConfiguration\nimport com.saveourtool.diktat.common.config.rules.RulesConfig\nimport com.saveourtool.diktat.common.config.rules.getRuleConfig\nimport com.saveourtool.diktat.ruleset.constants.Warnings.COMMENT_WHITE_SPACE\nimport com.saveourtool.diktat.ruleset.constants.Warnings.FIRST_COMMENT_NO_BLANK_LINE\nimport com.saveourtool.diktat.ruleset.constants.Warnings.IF_ELSE_COMMENTS\nimport com.saveourtool.diktat.ruleset.constants.Warnings.WRONG_NEWLINES_AROUND_KDOC\nimport com.saveourtool.diktat.ruleset.rules.DiktatRule\nimport com.saveourtool.diktat.ruleset.utils.commentType\nimport com.saveourtool.diktat.ruleset.utils.findAllDescendantsWithSpecificType\nimport com.saveourtool.diktat.ruleset.utils.findChildrenMatching\nimport com.saveourtool.diktat.ruleset.utils.getAllChildrenWithType\nimport com.saveourtool.diktat.ruleset.utils.getFirstChildWithType\nimport com.saveourtool.diktat.ruleset.utils.hasChildOfType\nimport com.saveourtool.diktat.ruleset.utils.isWhiteSpace\nimport com.saveourtool.diktat.ruleset.utils.isWhiteSpaceWithNewline\nimport com.saveourtool.diktat.ruleset.utils.leaveOnlyOneNewLine\nimport com.saveourtool.diktat.ruleset.utils.numNewLines\nimport com.saveourtool.diktat.ruleset.utils.prevNodeUntilNode\nimport com.saveourtool.diktat.ruleset.utils.prevSibling\nimport org.jetbrains.kotlin.KtNodeTypes.BLOCK\nimport org.jetbrains.kotlin.KtNodeTypes.CLASS\nimport org.jetbrains.kotlin.KtNodeTypes.CLASS_BODY\nimport org.jetbrains.kotlin.KtNodeTypes.ELSE\nimport org.jetbrains.kotlin.KtNodeTypes.FUN\nimport org.jetbrains.kotlin.KtNodeTypes.IF\nimport org.jetbrains.kotlin.KtNodeTypes.PROPERTY\nimport org.jetbrains.kotlin.KtNodeTypes.THEN\nimport org.jetbrains.kotlin.KtNodeTypes.VALUE_ARGUMENT_LIST\nimport org.jetbrains.kotlin.com.intellij.lang.ASTFactory\nimport org.jetbrains.kotlin.com.intellij.lang.ASTNode\nimport org.jetbrains.kotlin.com.intellij.psi.impl.source.tree.LeafPsiElement\nimport org.jetbrains.kotlin.com.intellij.psi.impl.source.tree.PsiWhiteSpaceImpl\nimport org.jetbrains.kotlin.kdoc.lexer.KDocTokens\nimport org.jetbrains.kotlin.kdoc.lexer.KDocTokens.KDOC\nimport org.jetbrains.kotlin.kdoc.parser.KDocElementTypes\nimport org.jetbrains.kotlin.lexer.KtTokens.BLOCK_COMMENT\nimport org.jetbrains.kotlin.lexer.KtTokens.ELSE_KEYWORD\nimport org.jetbrains.kotlin.lexer.KtTokens.EOL_COMMENT\nimport org.jetbrains.kotlin.lexer.KtTokens.LBRACE\nimport org.jetbrains.kotlin.lexer.KtTokens.WHITE_SPACE\nimport org.jetbrains.kotlin.psi.stubs.elements.KtFileElementType\n\n/**\n * This class handles rule 2.6\n * Part 1:\n * * there must be 1 space between the comment character and the content of the comment;\n * * there must be a newline between a Kdoc and the previous code above and no blank lines after.\n * * No need to add a blank line before a first comment in this particular name space (code block), for example between function declaration\n *   and first comment in a function body.\n *\n * Part 2:\n * * Leave one single space between the comment on the right side of the code and the code.\n * * Comments in if else should be inside code blocks. Exception: General if comment\n */\nclass CommentsFormatting(configRules: List<RulesConfig>) : DiktatRule(\n    NAME_ID,\n    configRules,\n    listOf(COMMENT_WHITE_SPACE, FIRST_COMMENT_NO_BLANK_LINE,\n        IF_ELSE_COMMENTS, WRONG_NEWLINES_AROUND_KDOC),\n) {\n    /**\n     * @param node\n     */\n    override fun logic(node: ASTNode) {\n        val configuration = CommentsFormattingConfiguration(\n            configRules.getRuleConfig(COMMENT_WHITE_SPACE)?.configuration ?: emptyMap())\n\n        when (node.elementType) {\n            CLASS, FUN, PROPERTY -> checkBlankLineAfterKdoc(node)\n            IF -> handleIfElse(node)\n            EOL_COMMENT, BLOCK_COMMENT -> handleEolAndBlockComments(node, configuration)\n            KDOC -> handleKdocComments(node, configuration)\n            else -> {\n                // this is a generated else block\n            }\n        }\n    }\n\n    @Suppress(\"PARAMETER_NAME_IN_OUTER_LAMBDA\")\n    private fun checkBlankLineAfterKdoc(node: ASTNode) {\n        commentType.forEach {\n            val kdoc = node.getFirstChildWithType(it)\n            kdoc?.treeNext?.let { nodeAfterKdoc ->\n                if (nodeAfterKdoc.elementType == WHITE_SPACE && nodeAfterKdoc.numNewLines() > 1) {\n                    WRONG_NEWLINES_AROUND_KDOC.warnAndFix(configRules, emitWarn, isFixMode, \"redundant blank line after ${kdoc.text}\", nodeAfterKdoc.startOffset, nodeAfterKdoc) {\n                        nodeAfterKdoc.leaveOnlyOneNewLine()\n                    }\n                }\n            }\n        }\n    }\n\n    private fun handleKdocComments(node: ASTNode, configuration: CommentsFormattingConfiguration) {\n        if (node.treeParent.treeParent != null && node.treeParent.treeParent.elementType == BLOCK) {\n            checkCommentsInCodeBlocks(node.treeParent)  // node.treeParent is a node that contains a comment.\n        } else if (node.treeParent.elementType != IF) {\n            checkClassComment(node)\n        }\n        checkWhiteSpaceBeginInComment(node, configuration)\n    }\n\n    private fun handleEolAndBlockComments(node: ASTNode, configuration: CommentsFormattingConfiguration) {\n        basicCommentsChecks(node, configuration)\n        checkWhiteSpaceBeginInComment(node, configuration)\n    }\n\n    private fun basicCommentsChecks(node: ASTNode, configuration: CommentsFormattingConfiguration) {\n        checkSpaceBeforeComment(node, configuration)\n\n        if (node.treeParent.elementType == BLOCK && node.treeNext != null) {\n            // Checking if comment is inside a code block like fun{}\n            // Not checking last comment as well\n            if (isFirstComment(node)) {\n                if (node.isChildOfBlockOrClassBody()) {\n                    // Just check white spaces before comment\n                    checkFirstCommentSpaces(node)\n                }\n                return\n            }\n        } else if (node.treeParent.lastChildNode != node && node.treeParent.elementType != IF &&\n                node.treeParent.firstChildNode == node && node.treeParent.elementType != VALUE_ARGUMENT_LIST) {\n            // Else it's a class comment\n            checkClassComment(node)\n        }\n    }\n\n    @Suppress(\"UnsafeCallOnNullableType\")\n    private fun handleIfElse(node: ASTNode) {\n        if (node.hasChildOfType(ELSE)) {\n            val elseKeyWord = node.getFirstChildWithType(ELSE_KEYWORD)!!\n            val elseBlock = node.getFirstChildWithType(ELSE)!!\n            val comment = when {\n                elseKeyWord.prevNodeUntilNode(THEN, EOL_COMMENT) != null -> elseKeyWord.prevNodeUntilNode(THEN, EOL_COMMENT)\n                elseKeyWord.prevNodeUntilNode(THEN, BLOCK_COMMENT) != null -> elseKeyWord.prevNodeUntilNode(THEN, BLOCK_COMMENT)\n                elseKeyWord.prevNodeUntilNode(THEN, KDOC) != null -> elseKeyWord.prevNodeUntilNode(THEN, KDOC)\n                else -> null\n            }\n            comment?.let {\n                IF_ELSE_COMMENTS.warnAndFix(configRules, emitWarn, isFixMode, comment.text, node.startOffset, node) {\n                    moveCommentToElse(node, elseBlock, elseKeyWord, comment)\n                }\n            }\n        }\n    }\n\n    @Suppress(\"UnsafeCallOnNullableType\")\n    private fun moveCommentToElse(node: ASTNode,\n                                  elseBlock: ASTNode,\n                                  elseKeyWord: ASTNode,\n                                  comment: ASTNode,\n    ) {\n        if (elseBlock.hasChildOfType(BLOCK)) {\n            val elseCodeBlock = elseBlock.getFirstChildWithType(BLOCK)!!\n            elseCodeBlock.addChild(comment,\n                elseCodeBlock.firstChildNode.treeNext)\n            elseCodeBlock.addChild(ASTFactory.whitespace(\"\\n\"),\n                elseCodeBlock.firstChildNode.treeNext)\n        } else {\n            elseKeyWord.treeParent.addChild(comment, elseKeyWord.treeNext)\n            elseKeyWord.treeParent.addChild(ASTFactory.whitespace(\"\\n\"), elseKeyWord.treeNext)\n        }\n\n        val whiteSpace = elseKeyWord.prevNodeUntilNode(THEN, WHITE_SPACE)\n\n        whiteSpace?.let {\n            node.removeChild(it)\n        }\n    }\n\n    private fun checkCommentsInCodeBlocks(node: ASTNode) {\n        if (isFirstComment(node)) {\n            if (node.isChildOfBlockOrClassBody()) {\n                // Just check white spaces before comment\n                checkFirstCommentSpaces(node)\n            }\n            return\n        }\n\n        if (!node.treePrev.isWhiteSpace()) {\n            // If node treePrev is not a whiteSpace then node treeParent is a property\n            WRONG_NEWLINES_AROUND_KDOC.warnAndFix(configRules, emitWarn, isFixMode, node.text, node.startOffset, node) {\n                node.treeParent.addChild(PsiWhiteSpaceImpl(\"\\n\"), node.treeParent)\n            }\n        } else {\n            if (node.treePrev.numNewLines() == 1 || node.treePrev.numNewLines() > 2) {\n                WRONG_NEWLINES_AROUND_KDOC.warnAndFix(configRules, emitWarn, isFixMode, node.text, node.startOffset, node) {\n                    (node.treePrev as LeafPsiElement).rawReplaceWithText(\"\\n\\n\")\n                }\n            }\n        }\n    }\n\n    private fun checkSpaceBeforeComment(node: ASTNode, configuration: CommentsFormattingConfiguration) {\n        if (node.treeParent.firstChildNode == node) {\n            return\n        }\n        if (node.treeParent.elementType == KtFileElementType.INSTANCE) {\n            // This case is for top-level comments that are located in the beginning of the line and therefore don't need any spaces before.\n            if (!node.treePrev.isWhiteSpaceWithNewline() && node.treePrev.text.count { it == ' ' } > 0) {\n                COMMENT_WHITE_SPACE.warnAndFix(configRules, emitWarn, isFixMode,\n                    \"There should be 0 space(s) before comment text, but are ${node.treePrev.text.count { it == ' ' }} in ${node.text}\",\n                    node.startOffset, node) {\n                    if (node.treePrev.elementType == WHITE_SPACE) {\n                        (node.treePrev as LeafPsiElement).rawReplaceWithText(\"\\n\")\n                    } else {\n                        node.treeParent.addChild(PsiWhiteSpaceImpl(\"\\n\"), node)\n                    }\n                }\n            }\n        } else if (!node.treePrev.isWhiteSpace()) {\n            // if comment is like this: val a = 5// Comment\n            COMMENT_WHITE_SPACE.warnAndFix(configRules, emitWarn, isFixMode,\n                \"There should be ${configuration.maxSpacesBeforeComment} space(s) before comment text, but are none in ${node.text}\", node.startOffset, node) {\n                node.treeParent.addChild(PsiWhiteSpaceImpl(\" \".repeat(configuration.maxSpacesBeforeComment)), node)\n            }\n        } else if (!node.treePrev.textContains('\\n') && node.treePrev.text.length != configuration.maxSpacesBeforeComment) {\n            // if there are too many or too few spaces before comment\n            val manyOrFew = when {\n                node.treePrev.text.length > configuration.maxSpacesBeforeComment -> \"many\"\n                else -> \"few\"\n            }\n            val message = \"There should be ${configuration.maxSpacesBeforeComment} space(s) before comment text, but there are too $manyOrFew in ${node.text}\"\n            COMMENT_WHITE_SPACE.warnAndFix(configRules, emitWarn, isFixMode,\n                message, node.startOffset, node) {\n                (node.treePrev as LeafPsiElement).rawReplaceWithText(\" \".repeat(configuration.maxSpacesBeforeComment))\n            }\n        }\n    }\n\n    @Suppress(\"ComplexMethod\", \"TOO_LONG_FUNCTION\")\n    private fun checkWhiteSpaceBeginInComment(node: ASTNode, configuration: CommentsFormattingConfiguration) {\n        if (node.elementType == EOL_COMMENT &&\n                node\n                    .text\n                    .trimStart('/')\n                    .takeWhile { it == ' ' }\n                    .length == configuration.maxSpacesInComment) {\n            return\n        }\n\n        if (node.elementType == BLOCK_COMMENT &&\n                (node.isIndentStyleComment() ||\n                        node\n                            .text\n                            .trim('/', '*')\n                            .takeWhile { it == ' ' }\n                            .length == configuration.maxSpacesInComment ||\n                        node\n                            .text\n                            .trim('/', '*')\n                            .takeWhile { it == '\\n' }\n                            .isNotEmpty())) {\n            return\n        }\n\n        if (node.elementType == KDOC) {\n            val section = node.getFirstChildWithType(KDocElementTypes.KDOC_SECTION)\n            if (section != null &&\n                    section.findChildrenMatching(KDocTokens.TEXT) { (it.treePrev != null && it.treePrev.elementType == KDocTokens.LEADING_ASTERISK) || it.treePrev == null }\n                        .all { it.text.startsWith(\" \".repeat(configuration.maxSpacesInComment)) }) {\n                // it.treePrev == null if there is no \\n at the beginning of KDoc\n                return\n            }\n\n            if (section != null &&\n                    section.getAllChildrenWithType(KDocTokens.CODE_BLOCK_TEXT).isNotEmpty() &&\n                    section.getAllChildrenWithType(KDocTokens.CODE_BLOCK_TEXT).all { it.text.startsWith(\" \".repeat(configuration.maxSpacesInComment)) }) {\n                return\n            }\n        }\n\n        COMMENT_WHITE_SPACE.warnAndFix(configRules, emitWarn, isFixMode,\n            \"There should be ${configuration.maxSpacesInComment} space(s) before comment token in ${node.text}\", node.startOffset, node) {\n            val commentText = node.text.drop(2).trim()\n\n            when (node.elementType) {\n                EOL_COMMENT -> (node as LeafPsiElement).rawReplaceWithText(\"// $commentText\")\n                BLOCK_COMMENT -> (node as LeafPsiElement).rawReplaceWithText(\"/* $commentText\")\n                KDOC -> {\n                    node.findAllDescendantsWithSpecificType(KDocTokens.TEXT).forEach {\n                        modifyKdocText(it, configuration)\n                    }\n                    node.findAllDescendantsWithSpecificType(KDocTokens.CODE_BLOCK_TEXT).forEach {\n                        modifyKdocText(it, configuration)\n                    }\n                }\n            }\n        }\n    }\n\n    private fun modifyKdocText(node: ASTNode, configuration: CommentsFormattingConfiguration) {\n        if (!node.text.startsWith(\" \".repeat(configuration.maxSpacesInComment))) {\n            val commentText = node.text.trim()\n            val indent = \" \".repeat(configuration.maxSpacesInComment)\n            (node as LeafPsiElement).rawReplaceWithText(\"$indent$commentText\")\n        }\n    }\n\n    private fun checkClassComment(node: ASTNode) {\n        if (isFirstComment(node)) {\n            if (node.isChildOfBlockOrClassBody()) {\n                checkFirstCommentSpaces(node)\n            } else {\n                checkFirstCommentSpaces(node.treeParent)\n            }\n        } else if (node.treeParent.elementType != KtFileElementType.INSTANCE && !node.treeParent.treePrev.isWhiteSpace()) {\n            // fixme: we might face more issues because newline node is inserted in a wrong place which causes consecutive\n            // white spaces to be split among nodes on different levels. But this requires investigation.\n            WRONG_NEWLINES_AROUND_KDOC.warnAndFix(configRules, emitWarn, isFixMode, node.text, node.startOffset, node) {\n                node.treeParent.treeParent.addChild(PsiWhiteSpaceImpl(\"\\n\"), node.treeParent)\n            }\n        } else if (node.treeParent.elementType != KtFileElementType.INSTANCE &&\n                (node.treeParent.treePrev.numNewLines() == 1 || node.treeParent.treePrev.numNewLines() > 2)) {\n            WRONG_NEWLINES_AROUND_KDOC.warnAndFix(configRules, emitWarn, isFixMode, node.text, node.startOffset, node) {\n                (node.treeParent.treePrev as LeafPsiElement).rawReplaceWithText(\"\\n\\n\")\n            }\n        }\n    }\n\n    private fun checkFirstCommentSpaces(node: ASTNode) {\n        if (node.treePrev.isWhiteSpace() &&\n                (node.treePrev.numNewLines() > 1 || node.treePrev.numNewLines() == 0)) {\n            FIRST_COMMENT_NO_BLANK_LINE.warnAndFix(configRules, emitWarn, isFixMode, node.text, node.startOffset, node) {\n                (node.treePrev as LeafPsiElement).rawReplaceWithText(\"\\n\")\n            }\n        }\n    }\n\n    private fun isFirstComment(node: ASTNode) = if (node.isChildOfBlockOrClassBody()) {\n        // In case when comment is inside of a function or class\n        if (node.treePrev.isWhiteSpace()) {\n            // in some cases (e.g. kts files) BLOCK doesn't have a leading brace\n            node.treePrev?.treePrev?.elementType == LBRACE\n        } else {\n            node.treePrev == null || node.treePrev.elementType == LBRACE  // null is handled for functional literal\n        }\n    } else if (node.treeParent?.treeParent?.elementType == KtFileElementType.INSTANCE && node.treeParent.prevSibling { it.text.isNotBlank() } == null) {\n        // `treeParent` is the first not-empty node in a file\n        true\n    } else if (node.treeParent.elementType != KtFileElementType.INSTANCE && node.treeParent.treePrev != null &&\n            node.treeParent.treePrev.treePrev != null) {\n        // When comment inside of a PROPERTY\n        node.treeParent\n            .treePrev\n            .treePrev\n            .elementType == LBRACE\n    } else {\n        node.treeParent.getAllChildrenWithType(node.elementType).first() == node\n    }\n\n    private fun ASTNode.isChildOfBlockOrClassBody(): Boolean = treeParent.elementType == BLOCK || treeParent.elementType == CLASS_BODY\n\n    /**\n     * Returns whether this block comment is a `indent`-style comment.\n     *\n     * `indent(1)` is a source code formatting utility for C-like languages.\n     * Historically, source code formatters are permitted to reformat and reflow\n     * the content of block comments, except for those comments which start with\n     * \"&#x2f;*-\".\n     *\n     * See also:\n     * - [5.1.1 Block Comments](https://www.oracle.com/java/technologies/javase/codeconventions-comments.html)\n     * - [`indent(1)`](https://man.openbsd.org/indent.1)\n     * - [`style(9)`](https://www.freebsd.org/cgi/man.cgi?query=style&sektion=9)\n     *\n     * @return `true` if this block comment is a `indent`-style comment, `false`\n     *   otherwise.\n     */\n    private fun ASTNode.isIndentStyleComment(): Boolean {\n        require(elementType == BLOCK_COMMENT) {\n            \"The elementType of this node is $elementType while $BLOCK_COMMENT expected\"\n        }\n\n        return text.matches(indentCommentMarker)\n    }\n\n    /**\n     * [RuleConfiguration] for [CommentsFormatting] rule\n     */\n    class CommentsFormattingConfiguration(config: Map<String, String>) : RuleConfiguration(config) {\n        /**\n         * Number of spaces before comment start\n         */\n        val maxSpacesBeforeComment = config[\"maxSpacesBeforeComment\"]?.toIntOrNull() ?: MAX_SPACES\n\n        /**\n         * Number of spaces after comment sign (`//` or other)\n         */\n        val maxSpacesInComment = config[\"maxSpacesInComment\"]?.toIntOrNull() ?: APPROPRIATE_COMMENT_SPACES\n    }\n    companion object {\n        private const val APPROPRIATE_COMMENT_SPACES = 1\n        private const val MAX_SPACES = 1\n        const val NAME_ID = \"kdoc-comments-codeblocks-formatting\"\n\n        /**\n         * \"&#x2f;*-\" followed by anything but `*` or `-`.\n         */\n        private val indentCommentMarker = Regex(\"\"\"(?s)^\\Q/*-\\E[^*-].*?\"\"\")\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/main/kotlin/com/saveourtool/diktat/ruleset/rules/chapter2/kdoc/KdocComments.kt",
    "content": "package com.saveourtool.diktat.ruleset.rules.chapter2.kdoc\n\nimport com.saveourtool.diktat.common.config.rules.RuleConfiguration\nimport com.saveourtool.diktat.common.config.rules.RulesConfig\nimport com.saveourtool.diktat.common.config.rules.getCommonConfiguration\nimport com.saveourtool.diktat.common.config.rules.getRuleConfig\nimport com.saveourtool.diktat.ruleset.constants.Warnings\nimport com.saveourtool.diktat.ruleset.constants.Warnings.COMMENTED_BY_KDOC\nimport com.saveourtool.diktat.ruleset.constants.Warnings.KDOC_DUPLICATE_PROPERTY\nimport com.saveourtool.diktat.ruleset.constants.Warnings.KDOC_EXTRA_PROPERTY\nimport com.saveourtool.diktat.ruleset.constants.Warnings.KDOC_NO_CLASS_BODY_PROPERTIES_IN_HEADER\nimport com.saveourtool.diktat.ruleset.constants.Warnings.KDOC_NO_CONSTRUCTOR_PROPERTY\nimport com.saveourtool.diktat.ruleset.constants.Warnings.KDOC_NO_CONSTRUCTOR_PROPERTY_WITH_COMMENT\nimport com.saveourtool.diktat.ruleset.constants.Warnings.MISSING_KDOC_CLASS_ELEMENTS\nimport com.saveourtool.diktat.ruleset.constants.Warnings.MISSING_KDOC_TOP_LEVEL\nimport com.saveourtool.diktat.ruleset.rules.DiktatRule\nimport com.saveourtool.diktat.ruleset.utils.*\n\nimport org.jetbrains.kotlin.KtNodeTypes.BLOCK\nimport org.jetbrains.kotlin.KtNodeTypes.CLASS\nimport org.jetbrains.kotlin.KtNodeTypes.CLASS_BODY\nimport org.jetbrains.kotlin.KtNodeTypes.FUN\nimport org.jetbrains.kotlin.KtNodeTypes.MODIFIER_LIST\nimport org.jetbrains.kotlin.KtNodeTypes.PRIMARY_CONSTRUCTOR\nimport org.jetbrains.kotlin.KtNodeTypes.PROPERTY\nimport org.jetbrains.kotlin.KtNodeTypes.TYPE_PARAMETER\nimport org.jetbrains.kotlin.KtNodeTypes.TYPE_PARAMETER_LIST\nimport org.jetbrains.kotlin.KtNodeTypes.TYPE_REFERENCE\nimport org.jetbrains.kotlin.KtNodeTypes.VALUE_PARAMETER\nimport org.jetbrains.kotlin.KtNodeTypes.VALUE_PARAMETER_LIST\nimport org.jetbrains.kotlin.com.intellij.lang.ASTNode\nimport org.jetbrains.kotlin.com.intellij.psi.impl.source.tree.LeafPsiElement\nimport org.jetbrains.kotlin.com.intellij.psi.impl.source.tree.PsiCommentImpl\nimport org.jetbrains.kotlin.com.intellij.psi.impl.source.tree.PsiWhiteSpaceImpl\nimport org.jetbrains.kotlin.com.intellij.psi.tree.TokenSet\nimport org.jetbrains.kotlin.kdoc.lexer.KDocTokens\nimport org.jetbrains.kotlin.kdoc.lexer.KDocTokens.KDOC\nimport org.jetbrains.kotlin.kdoc.parser.KDocElementTypes\nimport org.jetbrains.kotlin.kdoc.parser.KDocKnownTag\nimport org.jetbrains.kotlin.kdoc.psi.impl.KDocTag\nimport org.jetbrains.kotlin.lexer.KtTokens\nimport org.jetbrains.kotlin.lexer.KtTokens.BLOCK_COMMENT\nimport org.jetbrains.kotlin.lexer.KtTokens.EOL_COMMENT\nimport org.jetbrains.kotlin.lexer.KtTokens.IDENTIFIER\nimport org.jetbrains.kotlin.lexer.KtTokens.VAL_KEYWORD\nimport org.jetbrains.kotlin.lexer.KtTokens.VAR_KEYWORD\nimport org.jetbrains.kotlin.lexer.KtTokens.WHITE_SPACE\nimport org.jetbrains.kotlin.psi.psiUtil.parents\nimport org.jetbrains.kotlin.psi.psiUtil.siblings\nimport org.jetbrains.kotlin.psi.stubs.elements.KtFileElementType\n\n/**\n * This rule checks the following features in KDocs:\n * 1) All top-level (file level) functions and classes with public or internal access should have KDoc\n * 2) All internal elements in class like class, property or function should be documented with KDoc\n * 3) All non-private properties declared in the primary constructor are documented using `@property` tag in class KDoc\n */\nclass KdocComments(configRules: List<RulesConfig>) : DiktatRule(\n    NAME_ID,\n    configRules,\n    listOf(KDOC_EXTRA_PROPERTY, KDOC_NO_CONSTRUCTOR_PROPERTY,\n        KDOC_NO_CONSTRUCTOR_PROPERTY_WITH_COMMENT, MISSING_KDOC_CLASS_ELEMENTS, MISSING_KDOC_TOP_LEVEL,\n        KDOC_DUPLICATE_PROPERTY, COMMENTED_BY_KDOC\n    )\n) {\n    private val configuration by lazy {\n        KdocCommentsConfiguration(configRules.getRuleConfig(KDOC_NO_CONSTRUCTOR_PROPERTY)?.configuration ?: emptyMap())\n    }\n\n    /**\n     * @param node\n     */\n    override fun logic(node: ASTNode) {\n        val filePath = node.getFilePath()\n        val config = configRules.getCommonConfiguration()\n\n        if (!node.hasTestAnnotation() && !isLocatedInTest(filePath.splitPathToDirs(), config.testAnchors)) {\n            when (node.elementType) {\n                KtFileElementType.INSTANCE -> checkTopLevelDoc(node)\n                CLASS -> checkClassElements(node)\n                BLOCK -> checkKdocPresent(node)\n                else -> {\n                    // this is a generated else block\n                }\n            }\n        }\n    }\n\n    private fun checkKdocPresent(node: ASTNode) {\n        node.findChildrenMatching { it.elementType == KDOC }.forEach {\n            warnKdocInsideBlock(it)\n        }\n    }\n\n    private fun warnKdocInsideBlock(kdocNode: ASTNode) {\n        COMMENTED_BY_KDOC.warnAndFix(\n            configRules, emitWarn, isFixMode,\n            \"Redundant asterisk in block comment: \\\\**\", kdocNode.startOffset, kdocNode\n        ) {\n            kdocNode.treeParent.addChild(PsiCommentImpl(BLOCK_COMMENT, kdocNode.text.replace(\"/**\", \"/*\")), kdocNode)\n            kdocNode.treeParent.removeChild(kdocNode)\n        }\n    }\n\n    private fun checkParameterList(\n        classNode: ASTNode,\n        typeParameterListNode: ASTNode?,\n        valueParameterListNode: ASTNode?\n    ) {\n        if (typeParameterListNode == null && valueParameterListNode == null) {\n            return\n        }\n\n        val kdocBeforeClass = classNode.findChildByType(KDOC)\n            ?: return\n\n        val parametersInKdoc = kdocBeforeClass\n            .kDocTags()\n            .filter { it.knownTag == KDocKnownTag.PROPERTY || it.knownTag == KDocKnownTag.PARAM }\n\n        val getParametersFromListNode = { parameterListNode: ASTNode? ->\n            parameterListNode?.let { node ->\n                val parameterType = if (parameterListNode.elementType == TYPE_PARAMETER_LIST) TYPE_PARAMETER else VALUE_PARAMETER\n\n                node.findChildrenMatching { it.elementType == parameterType }\n                    .mapNotNull { it.findChildByType(IDENTIFIER)?.text }\n            } ?: emptyList()\n        }\n\n        val parametersInTypeParameterList = getParametersFromListNode(typeParameterListNode)\n        val parametersInValueParameterList = getParametersFromListNode(valueParameterListNode)\n\n        parametersInKdoc\n            .filter { it.getSubjectName() != null && it.getSubjectName() !in (parametersInTypeParameterList + parametersInValueParameterList) }\n            .forEach { KDOC_EXTRA_PROPERTY.warn(configRules, emitWarn, it.text, it.node.startOffset, classNode) }\n    }\n\n    @Suppress(\"UnsafeCallOnNullableType\", \"ComplexMethod\")\n    private fun checkValueParameter(classNode: ASTNode, valueParameterNode: ASTNode) {\n        if (valueParameterNode.parents().any { it.elementType == TYPE_REFERENCE }) {\n            return\n        }\n\n        val prevComment = if (valueParameterNode.siblings(forward = false)\n            .takeWhile { it.elementType != EOL_COMMENT && it.elementType != BLOCK_COMMENT }\n            .all { it.elementType == WHITE_SPACE }\n        ) {\n            // take previous comment, if it's immediately before `valueParameterNode` or separated only with white space\n            valueParameterNode.prevSibling { it.elementType == EOL_COMMENT || it.elementType == BLOCK_COMMENT }\n        } else if (valueParameterNode.hasChildOfType(KDOC)) {\n            valueParameterNode.findChildByType(KDOC)!!\n        } else {\n            null\n        }\n\n        val kdocBeforeClass = classNode.findChildByType(KDOC)\n        val isParamTagNeeded = (!valueParameterNode.hasChildOfType(VAL_KEYWORD) && !valueParameterNode.hasChildOfType(VAR_KEYWORD)) ||\n                !valueParameterNode.getFirstChildWithType(MODIFIER_LIST).isAccessibleOutside()\n\n        prevComment?.let {\n            kdocBeforeClass?.let {\n                checkKdocBeforeClass(valueParameterNode, kdocBeforeClass, prevComment, isParamTagNeeded)\n            }\n                ?: createKdocWithProperty(valueParameterNode, prevComment, isParamTagNeeded)\n        }\n            ?: kdocBeforeClass?.let {\n                checkBasicKdocBeforeClass(valueParameterNode, kdocBeforeClass, isParamTagNeeded)\n            }\n            ?: createKdocBasicKdoc(valueParameterNode, isParamTagNeeded)\n    }\n\n    @Suppress(\"UnsafeCallOnNullableType\", \"ComplexMethod\")\n    private fun checkTypeParameter(classNode: ASTNode, typeParameterNode: ASTNode) {\n        val kdocBeforeClass = classNode.findChildByType(KDOC)\n\n        kdocBeforeClass?.let {\n            checkBasicKdocBeforeClass(typeParameterNode, kdocBeforeClass, true)\n        } ?: createKdocBasicKdoc(typeParameterNode, true)\n    }\n\n    @Suppress(\"UnsafeCallOnNullableType\", \"ComplexMethod\")\n    private fun checkBasicKdocBeforeClass(\n        node: ASTNode,\n        kdocBeforeClass: ASTNode,\n        isParamTagNeeded: Boolean\n    ) {\n        val parameterName = getParameterName(node)\n        val parameterTagInClassKdoc = findParameterTagInClassKdoc(kdocBeforeClass, parameterName)\n\n        parameterTagInClassKdoc?.let {\n            val correctTag = if (isParamTagNeeded) KDocKnownTag.PARAM else KDocKnownTag.PROPERTY\n\n            if (parameterTagInClassKdoc.knownTag != correctTag) {\n                val warningText = if (isParamTagNeeded) {\n                    \"change `@property` tag to `@param` tag for <$parameterName> to KDoc\"\n                } else {\n                    \"change `@param` tag to `@property` tag for <$parameterName> to KDoc\"\n                }\n\n                KDOC_NO_CONSTRUCTOR_PROPERTY.warnAndFix(configRules, emitWarn, isFixMode, warningText, node.startOffset, node) {\n                    val isFirstTagInKdoc = parameterTagInClassKdoc.node == kdocBeforeClass.kDocTags().first().node\n                    replaceWrongTagInClassKdoc(kdocBeforeClass, parameterName, isParamTagNeeded, isFirstTagInKdoc)\n                }\n            }\n        } ?: run {\n            if (isNeedToWarn(node, isParamTagNeeded)) {\n                val warningText = if (isParamTagNeeded) \"add param <$parameterName> to KDoc\" else \"add property <$parameterName> to KDoc\"\n\n                KDOC_NO_CONSTRUCTOR_PROPERTY.warnAndFix(configRules, emitWarn, isFixMode, warningText, node.startOffset, node) {\n                    val newKdocText = if (isParamTagNeeded) \"* @param $parameterName\\n \" else \"* @property $parameterName\\n \"\n                    insertTextInKdoc(kdocBeforeClass, checkOneNewLineAfterKdocClassDescription(kdocBeforeClass, newKdocText, false))\n                }\n            }\n        }\n    }\n\n    private fun isNeedToWarn(node: ASTNode, isParamTagNeeded: Boolean): Boolean {\n        val isParameter = node.elementType == VALUE_PARAMETER && !node.hasChildOfType(VAL_KEYWORD) && !node.hasChildOfType(VAR_KEYWORD)\n        val isPrivateProperty = node.elementType == VALUE_PARAMETER && !node.getFirstChildWithType(MODIFIER_LIST).isAccessibleOutside()\n        val isTypeParameterNode = node.elementType == TYPE_PARAMETER\n\n        return !isParamTagNeeded ||\n                (isParameter && configuration.isParamTagsForParameters) ||\n                (isPrivateProperty && configuration.isParamTagsForPrivateProperties) ||\n                (isTypeParameterNode && configuration.isParamTagsForGenericTypes)\n    }\n\n    private fun replaceWrongTagInClassKdoc(\n        kdocBeforeClass: ASTNode,\n        parameterName: String,\n        isParamTagNeeded: Boolean,\n        isFirstTagInKdoc: Boolean\n    ) {\n        val wrongTagText = if (isParamTagNeeded) \"* @property $parameterName\" else \"* @param $parameterName\"\n        val replaceText = if (isParamTagNeeded) \"* @param $parameterName\" else \"* @property $parameterName\"\n\n        changeTagInKdoc(kdocBeforeClass, wrongTagText, checkOneNewLineAfterKdocClassDescription(kdocBeforeClass, replaceText, isFirstTagInKdoc))\n    }\n\n    @Suppress(\"UnsafeCallOnNullableType\")\n    private fun changeTagInKdoc(\n        kdocBeforeClass: ASTNode,\n        wrongTagText: String,\n        correctTagText: String\n    ) {\n        val allKdocText = kdocBeforeClass.text\n        val newKdocText = allKdocText.replaceFirst(wrongTagText, correctTagText)\n        kdocBeforeClass.treeParent.replaceChild(kdocBeforeClass, KotlinParser().createNode(newKdocText).findChildByType(KDOC)!!)\n    }\n\n    @Suppress(\"UnsafeCallOnNullableType\")\n    private fun checkOneNewLineAfterKdocClassDescription(\n        kdocBeforeClass: ASTNode,\n        newKdocText: String,\n        isFirstTagInKdoc: Boolean\n    ): String {\n        val firstDescriptionSection = kdocBeforeClass\n            .findChildrenMatching { it.elementType == KDocElementTypes.KDOC_SECTION }\n            .firstOrNull()\n        val lastTextInDescription = firstDescriptionSection\n            ?.findChildrenMatching { it.elementType == KDocTokens.TEXT || it.elementType == KDocTokens.CODE_BLOCK_TEXT || it.elementType == KDocTokens.MARKDOWN_LINK }\n            ?.lastOrNull { it.text.trim().isNotEmpty() }\n\n        val isHasDescription = lastTextInDescription != null\n\n        return newKdocText.let {text ->\n            if (isHasDescription && (kdocBeforeClass.kDocTags().isEmpty() || isFirstTagInKdoc)) {\n                // if we have any existing tags and current is first of them, we need to save last three nodes which are KDOC_LEADING_ASTERISK and two WHITE_SPACE around it\n                // this is necessary so that first tag is on new line immediately after description\n                val beforeChild = if (isFirstTagInKdoc) firstDescriptionSection!!.lastChildNode.treePrev.treePrev.treePrev else firstDescriptionSection!!.lastChildNode\n\n                // remove all KDOC_LEADING_ASTERISK and WHITE_SPACE between last text in description and end of description\n                firstDescriptionSection\n                    .findChildrenMatching {\n                        firstDescriptionSection.isChildAfterAnother(it, lastTextInDescription!!) &&\n                                (firstDescriptionSection.isChildBeforeAnother(it, beforeChild) || it == beforeChild)\n                    }\n                    .forEach { firstDescriptionSection.removeChild(it) }\n\n                \"*\\n $text\"\n            } else {\n                text\n            }\n        }\n    }\n\n    private fun checkKdocBeforeClass(\n        node: ASTNode,\n        kdocBeforeClass: ASTNode,\n        prevComment: ASTNode,\n        isParamTagNeeded: Boolean\n    ) {\n        if (prevComment.elementType == KDOC || prevComment.elementType == BLOCK_COMMENT) {\n            // there is a documentation before property or parameter that we can extract, and there is class KDoc, where we can move it to\n            handleKdocAndBlock(node, kdocBeforeClass, prevComment, isParamTagNeeded)\n        } else {\n            handleCommentBefore(node, kdocBeforeClass, prevComment, isParamTagNeeded)\n        }\n    }\n\n    @Suppress(\"UnsafeCallOnNullableType\")\n    private fun createKdocBasicKdoc(node: ASTNode, isParamTagNeeded: Boolean) {\n        if (isNeedToWarn(node, isParamTagNeeded)) {\n            val parameterName = getParameterName(node)\n            val warningText = if (isParamTagNeeded) \"add param <$parameterName> to KDoc\" else \"add property <$parameterName> to KDoc\"\n\n            KDOC_NO_CONSTRUCTOR_PROPERTY.warnAndFix(configRules, emitWarn, isFixMode, warningText, node.startOffset, node) {\n                val classNode = node.parent { it.elementType == CLASS }!!\n                val newKdocText = if (isParamTagNeeded) \"/**\\n * @param $parameterName\\n */\" else \"/**\\n * @property $parameterName\\n */\"\n                val newKdoc = KotlinParser().createNode(newKdocText)\n\n                classNode.addChild(PsiWhiteSpaceImpl(\"\\n\"), classNode.firstChildNode)\n                classNode.addChild(newKdoc.findChildByType(KDOC)!!, classNode.firstChildNode)\n            }\n        }\n    }\n\n    @Suppress(\"UnsafeCallOnNullableType\")\n    private fun createKdocWithProperty(\n        node: ASTNode,\n        prevComment: ASTNode,\n        isParamTagNeeded: Boolean\n    ) {\n        if (isNeedToWarn(node, isParamTagNeeded)) {\n            val parameterName = getParameterName(node)\n            val classNode = node.parent { it.elementType == CLASS }!!\n\n            // if property or parameter is documented with KDoc, which has a tag inside, then it can contain some additional more\n            // complicated structure, that will be hard to move automatically\n            val isHasTagsInConstructorKdoc = prevComment.elementType == KDOC && prevComment.kDocTags().isNotEmpty()\n            val isFixable = !isHasTagsInConstructorKdoc\n            val warningText = if (isParamTagNeeded) \"add comment for param <$parameterName> to KDoc\" else \"add comment for property <$parameterName> to KDoc\"\n\n            KDOC_NO_CONSTRUCTOR_PROPERTY_WITH_COMMENT.warnOnlyOrWarnAndFix(configRules, emitWarn, warningText, prevComment.startOffset, node, isFixable, isFixMode) {\n                val paramOrPropertyTagText = if (isParamTagNeeded) \"@param\" else \"@property\"\n                val newKdocText = createClassKdocTextFromComment(prevComment, parameterName, paramOrPropertyTagText)\n                val newKdoc = KotlinParser().createNode(newKdocText).findChildByType(KDOC)!!\n\n                classNode.addChild(PsiWhiteSpaceImpl(\"\\n\"), classNode.firstChildNode)\n                classNode.addChild(newKdoc, classNode.firstChildNode)\n                node.removeWithWhiteSpace(prevComment)\n            }\n        }\n    }\n\n    private fun createClassKdocTextFromComment(\n        prevComment: ASTNode,\n        parameterName: String,\n        paramOrPropertyTagText: String\n    ) = when (prevComment.elementType) {\n        KDOC -> \"/**\\n * $paramOrPropertyTagText $parameterName${createClassKdocTextFromKdocComment(prevComment)}\\n */\"\n        EOL_COMMENT -> \"/**\\n * $paramOrPropertyTagText $parameterName ${createClassKdocTextFromEolComment(prevComment)}\\n */\"\n        else -> \"/**\\n * $paramOrPropertyTagText $parameterName${createClassKdocTextFromBlockComment(prevComment)}\\n */\"\n    }\n\n    private fun createClassKdocTextFromKdocComment(prevComment: ASTNode) =\n        prevComment.text\n            .removePrefix(\"/**\")\n            .removeSuffix(\"*/\")\n            .replace(\"\\n( )*\\\\*( )*\".toRegex(), \"\\n *   \")\n            .trimStart(' ')\n            .trimEnd(' ', '\\n')\n            .let { if (!it.startsWith(\"\\n\")) \" $it\" else it }\n\n    private fun createClassKdocTextFromEolComment(prevComment: ASTNode) =\n        prevComment.text\n            .removePrefix(\"//\")\n            .trimStart(' ')\n            .trimEnd(' ', '\\n')\n\n    private fun createClassKdocTextFromBlockComment(prevComment: ASTNode) =\n        prevComment.text\n            .removePrefix(\"/*\")\n            .removeSuffix(\"*/\")\n            .replace(\"\\n( )*\\\\*( )*\".toRegex(), \"\\n *   \")\n            .trimStart(' ')\n            .trimEnd(' ', '\\n')\n            .let { if (!it.startsWith(\"\\n\")) \" $it\" else it }\n\n    @Suppress(\n        \"UnsafeCallOnNullableType\",\n        \"TOO_LONG_FUNCTION\",\n        \"ComplexMethod\"\n    )\n    private fun handleKdocAndBlock(\n        node: ASTNode,\n        kdocBeforeClass: ASTNode,\n        prevComment: ASTNode,\n        isParamTagNeeded: Boolean\n    ) {\n        val parameterName = getParameterName(node)\n        val parameterTagInClassKdoc = findParameterTagInClassKdoc(kdocBeforeClass, parameterName)\n        val parameterInClassKdoc = parameterTagInClassKdoc?.node\n\n        val commentText = if (prevComment.elementType == KDOC) {\n            createClassKdocTextFromKdocComment(prevComment)\n        } else {\n            createClassKdocTextFromBlockComment(prevComment)\n        }\n\n        // if property or parameter is documented with KDoc, which has a tag inside, then it can contain some additional more\n        // complicated structure, that will be hard to move automatically\n        val isHasTagsInConstructorKdoc = prevComment.elementType == KDOC && prevComment.kDocTags().isNotEmpty()\n        val isFixable = !isHasTagsInConstructorKdoc\n\n        val (isHasWrongTag, warningText) = checkWrongTagAndMakeWarningText(parameterTagInClassKdoc, parameterName, isParamTagNeeded)\n        val isFirstTagInKdoc = parameterTagInClassKdoc?.node != null && parameterTagInClassKdoc.node == kdocBeforeClass.kDocTags().first().node\n\n        parameterInClassKdoc?.let {\n            KDOC_NO_CONSTRUCTOR_PROPERTY_WITH_COMMENT.warnOnlyOrWarnAndFix(configRules, emitWarn, warningText, prevComment.startOffset, node, isFixable, isFixMode) {\n                // local docs should be appended to docs in class\n                appendKdocTagContent(parameterInClassKdoc, commentText)\n\n                if (isHasWrongTag) {\n                    replaceWrongTagInClassKdoc(kdocBeforeClass, parameterName, isParamTagNeeded, isFirstTagInKdoc)\n                }\n\n                node.removeWithWhiteSpace(prevComment)\n            }\n        }\n            ?: run {\n                if (isNeedToWarn(node, isParamTagNeeded)) {\n                    KDOC_NO_CONSTRUCTOR_PROPERTY_WITH_COMMENT.warnOnlyOrWarnAndFix(configRules, emitWarn, warningText, prevComment.startOffset, node, isFixable, isFixMode) {\n                        val newKdocText = if (isParamTagNeeded) \"* @param $parameterName$commentText\\n \" else \"* @property $parameterName$commentText\\n \"\n                        insertTextInKdoc(kdocBeforeClass, checkOneNewLineAfterKdocClassDescription(kdocBeforeClass, newKdocText, isFirstTagInKdoc))\n\n                        node.removeWithWhiteSpace(prevComment)\n                    }\n                }\n            }\n    }\n\n    @Suppress(\n        \"UnsafeCallOnNullableType\",\n        \"TOO_LONG_FUNCTION\",\n        \"ComplexMethod\"\n    )\n    private fun handleCommentBefore(\n        node: ASTNode,\n        kdocBeforeClass: ASTNode,\n        prevComment: ASTNode,\n        isParamTagNeeded: Boolean\n    ) {\n        val parameterName = getParameterName(node)\n        val parameterTagInClassKdoc = findParameterTagInClassKdoc(kdocBeforeClass, parameterName)\n        val parameterInClassKdoc = parameterTagInClassKdoc?.node\n\n        val (isHasWrongTag, warningText) = checkWrongTagAndMakeWarningText(parameterTagInClassKdoc, parameterName, isParamTagNeeded)\n        val isFirstTagInKdoc = parameterTagInClassKdoc?.node != null && parameterTagInClassKdoc.node == kdocBeforeClass.kDocTags().first().node\n\n        parameterInClassKdoc?.let {\n            KDOC_NO_CONSTRUCTOR_PROPERTY_WITH_COMMENT.warnAndFix(configRules, emitWarn, isFixMode, warningText, prevComment.startOffset, node) {\n                if (parameterInClassKdoc.hasChildOfType(KDocTokens.TEXT)) {\n                    val newKdocText = parameterInClassKdoc\n                        .findChildrenMatching { it.elementType == KDocTokens.TEXT || it.elementType == KDocTokens.CODE_BLOCK_TEXT }\n                        .lastOrNull()\n                    (newKdocText as LeafPsiElement).rawReplaceWithText(\"${newKdocText.text}\\n *   ${createClassKdocTextFromEolComment(prevComment)}\")\n                } else {\n                    parameterInClassKdoc.addChild(LeafPsiElement(KDocTokens.TEXT, \" ${createClassKdocTextFromEolComment(prevComment)}\"), null)\n                }\n\n                if (isHasWrongTag) {\n                    replaceWrongTagInClassKdoc(kdocBeforeClass, parameterName, isParamTagNeeded, isFirstTagInKdoc)\n                }\n\n                node.treeParent.removeChildMergingSurroundingWhitespaces(prevComment.treePrev, prevComment, prevComment.treeNext)\n            }\n        }\n            ?: run {\n                if (isNeedToWarn(node, isParamTagNeeded)) {\n                    KDOC_NO_CONSTRUCTOR_PROPERTY_WITH_COMMENT.warnAndFix(configRules, emitWarn, isFixMode, warningText, prevComment.startOffset, node) {\n                        val newKdocText = if (isParamTagNeeded) {\n                            \"* @param $parameterName ${createClassKdocTextFromEolComment(prevComment)}\\n \"\n                        } else {\n                            \"* @property $parameterName ${createClassKdocTextFromEolComment(prevComment)}\\n \"\n                        }\n\n                        insertTextInKdoc(kdocBeforeClass, checkOneNewLineAfterKdocClassDescription(kdocBeforeClass, newKdocText, isFirstTagInKdoc))\n\n                        node.treeParent.removeChildMergingSurroundingWhitespaces(prevComment.treePrev, prevComment, prevComment.treeNext)\n                    }\n                }\n            }\n    }\n\n    @Suppress(\"UnsafeCallOnNullableType\")\n    private fun getParameterName(node: ASTNode) = node.findChildByType(IDENTIFIER)!!.text.replace(\"`\", \"\")\n\n    private fun findParameterTagInClassKdoc(kdocBeforeClass: ASTNode, parameterName: String) =\n        kdocBeforeClass\n            .kDocTags()\n            .firstOrNull { (it.knownTag == KDocKnownTag.PARAM || it.knownTag == KDocKnownTag.PROPERTY) && it.getSubjectName() == parameterName }\n\n    private fun checkWrongTagAndMakeWarningText(\n        parameterTagInClassKdoc: KDocTag?,\n        parameterName: String,\n        isParamTagNeeded: Boolean\n    ): Pair<Boolean, String> {\n        val correctTag = if (isParamTagNeeded) KDocKnownTag.PARAM else KDocKnownTag.PROPERTY\n        val isHasWrongTag = parameterTagInClassKdoc != null && parameterTagInClassKdoc.knownTag != correctTag\n        val warningText = if (isHasWrongTag) {\n            if (isParamTagNeeded) {\n                \"change `@property` tag to `@param` tag for <$parameterName> and add comment to KDoc\"\n            } else {\n                \"change `@param` tag to `@property` tag for <$parameterName> and add comment to KDoc\"\n            }\n        } else {\n            if (isParamTagNeeded) {\n                \"add comment for param <$parameterName> to KDoc\"\n            } else {\n                \"add comment for property <$parameterName> to KDoc\"\n            }\n        }\n\n        return Pair(isHasWrongTag, warningText)\n    }\n\n    private fun checkDuplicateProperties(kdoc: ASTNode) {\n        val propertiesAndParams = kdoc\n            .kDocTags()\n            .filter { it.knownTag == KDocKnownTag.PROPERTY || it.knownTag == KDocKnownTag.PARAM }\n        val traversedNodes: MutableSet<String?> = mutableSetOf()\n        propertiesAndParams.forEach { parameter ->\n            if (!traversedNodes.add(parameter.getSubjectName())) {\n                KDOC_DUPLICATE_PROPERTY.warn(configRules, emitWarn, parameter.text, parameter.node.startOffset, kdoc)\n            }\n        }\n    }\n\n    @Suppress(\"UnsafeCallOnNullableType\")\n    private fun insertTextInKdoc(kdocBeforeClass: ASTNode, insertText: String) {\n        val allKdocText = kdocBeforeClass.text\n        val endKdoc = kdocBeforeClass.findChildByType(KDocTokens.END)!!.text\n        val newKdocText = StringBuilder(allKdocText).insert(allKdocText.indexOf(endKdoc), insertText).toString()\n        kdocBeforeClass.treeParent.replaceChild(kdocBeforeClass, KotlinParser().createNode(newKdocText).findChildByType(KDOC)!!)\n    }\n\n    /**\n     * Append [content] to [kdocTagNode], e.g.\n     * (`@property foo bar`, \"baz\") -> `@property foo bar baz`\n     */\n    private fun appendKdocTagContent(kdocTagNode: ASTNode, content: String) {\n        kdocTagNode.findChildrenMatching { it.elementType == KDocTokens.TEXT || it.elementType == KDocTokens.CODE_BLOCK_TEXT }\n            .lastOrNull()\n            ?.let {\n                kdocTagNode.replaceChild(\n                    it,\n                    LeafPsiElement(KDocTokens.TEXT, \"${it.text}$content\"),\n                )\n            } ?: kdocTagNode.addChild(LeafPsiElement(KDocTokens.TEXT, content), null)\n    }\n\n    private fun checkClassElements(classNode: ASTNode) {\n        val modifierList = classNode.getFirstChildWithType(MODIFIER_LIST)\n        val typeParameterList = classNode.getFirstChildWithType(TYPE_PARAMETER_LIST)\n        val valueParameterList = classNode.getFirstChildWithType(PRIMARY_CONSTRUCTOR)?.getFirstChildWithType(VALUE_PARAMETER_LIST)\n        val classBody = classNode.getFirstChildWithType(CLASS_BODY)\n        val classKdoc = classNode.getFirstChildWithType(KDOC)\n\n        checkParameterList(classNode, typeParameterList, valueParameterList)\n\n        typeParameterList\n            ?.findChildrenMatching { it.elementType == TYPE_PARAMETER }\n            ?.forEach { checkTypeParameter(classNode, it) }\n\n        valueParameterList\n            ?.findChildrenMatching { it.elementType == VALUE_PARAMETER }\n            ?.forEach { checkValueParameter(classNode, it) }\n\n        // if parent class is public or internal than we can check it's internal code elements\n        if (classBody != null && modifierList.isAccessibleOutside()) {\n            classBody\n                .getChildren(statementsToDocument)\n                .filterNot {\n                    (it.elementType == FUN && it.isStandardMethod()) || (it.elementType == FUN && it.isOverridden()) || (it.elementType == PROPERTY && it.isOverridden())\n                }\n                .forEach { classElement ->\n                    if (classElement.elementType == PROPERTY) {\n                        // we check if property declared in class body is also documented in class header via\n                        // `@property` tag\n                        val propertyInClassKdoc = classKdoc?.kDocTags()?.find {\n                            it.knownTag == KDocKnownTag.PROPERTY && it.getSubjectName() == classElement.getIdentifierName()?.text\n                        }\n                        propertyInClassKdoc?.let {\n                            // if property is documented as `@property`, then we suggest to move docs to the\n                            // declaration inside the class body\n                            KDOC_NO_CLASS_BODY_PROPERTIES_IN_HEADER.warn(configRules, emitWarn, classElement.text, classElement.startOffset, classElement)\n                            return\n                        }\n                    }\n                    // for everything else, we raise a missing kdoc warning\n                    checkDoc(classElement, MISSING_KDOC_CLASS_ELEMENTS)\n                }\n        }\n    }\n\n    private fun checkTopLevelDoc(node: ASTNode) {\n        // checking that all top level class declarations and functions have kDoc\n        return (node.getAllChildrenWithType(CLASS) + node.getAllChildrenWithType(FUN))\n            .forEach { checkDoc(it, MISSING_KDOC_TOP_LEVEL) }\n    }\n\n    /**\n     * raises warning if protected, public or internal code element does not have a Kdoc\n     */\n    @Suppress(\"UnsafeCallOnNullableType\")\n    private fun checkDoc(node: ASTNode, warning: Warnings) {\n        // if there is an annotation before function, AST is a bit more complex, so we need to look for Kdoc among\n        // children of modifier list\n        val kdoc = node.getFirstChildWithType(KDOC) ?: node.getFirstChildWithType(MODIFIER_LIST)?.getFirstChildWithType(KDOC)\n        kdoc?.let {\n            checkDuplicateProperties(kdoc)\n        }\n        val name = node.getIdentifierName()\n        val isModifierAccessibleOutsideOrActual = node.getFirstChildWithType(MODIFIER_LIST).run {\n            isAccessibleOutside() && this?.hasChildOfType(KtTokens.ACTUAL_KEYWORD) != true\n        }\n\n        if (isModifierAccessibleOutsideOrActual && kdoc == null && !isTopLevelFunctionStandard(node)) {\n            warning.warn(configRules, emitWarn, name!!.text, node.startOffset, node)\n        }\n    }\n\n    private fun isTopLevelFunctionStandard(node: ASTNode): Boolean = node.elementType == FUN && node.isStandardMethod()\n\n    /**\n     * [RuleConfiguration] for param tags creation\n     */\n    private class KdocCommentsConfiguration(config: Map<String, String>) : RuleConfiguration(config) {\n        /**\n         * Create param tags for parameters without val or var\n         */\n        val isParamTagsForParameters = config[\"isParamTagsForParameters\"]?.toBoolean() ?: true\n\n        /**\n         * Create param tags for private properties\n         */\n        val isParamTagsForPrivateProperties = config[\"isParamTagsForPrivateProperties\"]?.toBoolean() ?: true\n\n        /**\n         * Create param tags for generic types\n         */\n        val isParamTagsForGenericTypes = config[\"isParamTagsForGenericTypes\"]?.toBoolean() ?: true\n    }\n\n    companion object {\n        const val NAME_ID = \"kdoc-comments\"\n        private val statementsToDocument = TokenSet.create(CLASS, FUN, PROPERTY)\n    }\n}\n\nprivate fun ASTNode.removeWithWhiteSpace(prevComment: ASTNode) {\n    removeChildMergingSurroundingWhitespaces(\n        if (prevComment.elementType == KDOC) prevComment.treeParent.treePrev else prevComment.treePrev,\n        prevComment, prevComment.treeNext\n    )\n}\n\n/**\n * If [child] node is surrounded by nodes with type `WHITE_SPACE`, remove [child] and merge surrounding nodes,\n * preserving only a single newline if present (i.e. leaving no empty lines after merging). In any case, [child] is removed\n * from the tree.\n */\nprivate fun ASTNode.removeChildMergingSurroundingWhitespaces(\n    prevWhiteSpaces: ASTNode,\n    child: ASTNode,\n    nextWhitespaces: ASTNode\n) {\n    if (nextWhitespaces.elementType == WHITE_SPACE && prevWhiteSpaces.elementType == WHITE_SPACE) {\n        val mergedText = (prevWhiteSpaces.text + nextWhitespaces.text)\n        val mergedSpace = if (mergedText.contains('\\n')) {\n            '\\n' + mergedText.substringAfterLast('\\n')\n        } else {\n            mergedText\n        }\n\n        child.treeParent.removeChild(prevWhiteSpaces)\n        child.treeParent.replaceWhiteSpaceText(nextWhitespaces, mergedSpace)\n    }\n    removeChild(child)\n}\n"
  },
  {
    "path": "diktat-rules/src/main/kotlin/com/saveourtool/diktat/ruleset/rules/chapter2/kdoc/KdocFormatting.kt",
    "content": "package com.saveourtool.diktat.ruleset.rules.chapter2.kdoc\n\nimport com.saveourtool.diktat.common.config.rules.RuleConfiguration\nimport com.saveourtool.diktat.common.config.rules.RulesConfig\nimport com.saveourtool.diktat.common.config.rules.getRuleConfig\nimport com.saveourtool.diktat.ruleset.constants.Warnings.KDOC_CONTAINS_DATE_OR_AUTHOR\nimport com.saveourtool.diktat.ruleset.constants.Warnings.KDOC_EMPTY_KDOC\nimport com.saveourtool.diktat.ruleset.constants.Warnings.KDOC_NEWLINES_BEFORE_BASIC_TAGS\nimport com.saveourtool.diktat.ruleset.constants.Warnings.KDOC_NO_DEPRECATED_TAG\nimport com.saveourtool.diktat.ruleset.constants.Warnings.KDOC_NO_EMPTY_TAGS\nimport com.saveourtool.diktat.ruleset.constants.Warnings.KDOC_NO_NEWLINES_BETWEEN_BASIC_TAGS\nimport com.saveourtool.diktat.ruleset.constants.Warnings.KDOC_NO_NEWLINE_AFTER_SPECIAL_TAGS\nimport com.saveourtool.diktat.ruleset.constants.Warnings.KDOC_WRONG_SPACES_AFTER_TAG\nimport com.saveourtool.diktat.ruleset.constants.Warnings.KDOC_WRONG_TAGS_ORDER\nimport com.saveourtool.diktat.ruleset.rules.DiktatRule\nimport com.saveourtool.diktat.ruleset.utils.allSiblings\nimport com.saveourtool.diktat.ruleset.utils.findChildAfter\nimport com.saveourtool.diktat.ruleset.utils.findChildBefore\nimport com.saveourtool.diktat.ruleset.utils.getAllChildrenWithType\nimport com.saveourtool.diktat.ruleset.utils.getFirstChildWithType\nimport com.saveourtool.diktat.ruleset.utils.getIdentifierName\nimport com.saveourtool.diktat.ruleset.utils.hasChildMatching\nimport com.saveourtool.diktat.ruleset.utils.hasTrailingNewlineInTagBody\nimport com.saveourtool.diktat.ruleset.utils.isWhiteSpaceWithNewline\nimport com.saveourtool.diktat.ruleset.utils.kDocTags\nimport com.saveourtool.diktat.ruleset.utils.leaveOnlyOneNewLine\nimport com.saveourtool.diktat.ruleset.utils.nextSibling\nimport com.saveourtool.diktat.ruleset.utils.prevSibling\nimport com.saveourtool.diktat.ruleset.utils.reversedChildren\n\nimport org.jetbrains.kotlin.KtNodeTypes\nimport org.jetbrains.kotlin.com.intellij.lang.ASTNode\nimport org.jetbrains.kotlin.com.intellij.psi.impl.source.tree.CompositeElement\nimport org.jetbrains.kotlin.com.intellij.psi.impl.source.tree.LeafPsiElement\nimport org.jetbrains.kotlin.com.intellij.psi.impl.source.tree.PsiWhiteSpaceImpl\nimport org.jetbrains.kotlin.com.intellij.psi.tree.IElementType\nimport org.jetbrains.kotlin.kdoc.lexer.KDocTokens\nimport org.jetbrains.kotlin.kdoc.lexer.KDocTokens.KDOC\nimport org.jetbrains.kotlin.kdoc.parser.KDocElementTypes\nimport org.jetbrains.kotlin.kdoc.parser.KDocKnownTag\nimport org.jetbrains.kotlin.kdoc.psi.impl.KDocTag\nimport org.jetbrains.kotlin.lexer.KtTokens\nimport org.jetbrains.kotlin.lexer.KtTokens.WHITE_SPACE\nimport org.jetbrains.kotlin.psi.psiUtil.startOffset\n\nimport java.time.format.DateTimeFormatter\nimport java.time.temporal.ChronoField\n\n/**\n * Formatting visitor for Kdoc:\n * 1) removing all blank lines between Kdoc and the code it's declaring\n * 2) ensuring there are no tags with empty content\n * 3) ensuring there is only one white space between tag and it's body\n * 4) ensuring tags @apiNote, @implSpec, @implNote have one empty line after their body\n * 5) ensuring tags @param, @return, @throws are arranged in this order\n * 6) ensuring @author tag is not used\n * 7) ensuring @since tag contains only versions and not dates\n */\n@Suppress(\"ForbiddenComment\")\nclass KdocFormatting(configRules: List<RulesConfig>) : DiktatRule(\n    NAME_ID,\n    configRules,\n    listOf(KDOC_CONTAINS_DATE_OR_AUTHOR, KDOC_EMPTY_KDOC, KDOC_NEWLINES_BEFORE_BASIC_TAGS, KDOC_NO_DEPRECATED_TAG,\n        KDOC_NO_EMPTY_TAGS, KDOC_NO_NEWLINES_BETWEEN_BASIC_TAGS, KDOC_NO_NEWLINE_AFTER_SPECIAL_TAGS,\n        KDOC_WRONG_SPACES_AFTER_TAG, KDOC_WRONG_TAGS_ORDER),\n) {\n    /**\n     * The reasoning behind the tag ordering:\n     *\n     * 1. `@receiver` documents `this` instance which is the 1st function call\n     *    parameter (ordered before `@param`).\n     * 1. `@param` followed by `@return`, then followed by `@throws` or\n     *    `@exception` is the conventional order inherited from _JavaDoc_.\n     * 1. `@param` tags can also be used to document generic type parameters.\n     * 1. `@property` tags are placed after `@param` tags in the official\n     *    [example](https://kotlinlang.org/docs/kotlin-doc.html#kdoc-syntax). Looking at the\n     *    [code](https://github.com/JetBrains/kotlin/blob/master/libraries/stdlib/src/kotlin/util/Tuples.kt#L22),\n     *    this is also the style _JetBrains_ use themselves.\n     * 1. looking at the examples, `@constructor` tags are placed last in\n     *    constructor descriptions.\n     */\n    private val basicTagsList = listOf(\n        KDocKnownTag.RECEIVER,\n        KDocKnownTag.PARAM,\n        KDocKnownTag.PROPERTY,\n        KDocKnownTag.RETURN,\n        KDocKnownTag.THROWS,\n        KDocKnownTag.EXCEPTION,\n        KDocKnownTag.CONSTRUCTOR,\n    )\n    private val specialTagNames = setOf(\"implSpec\", \"implNote\", \"apiNote\")\n    private var versionRegex: Regex? = null\n\n    /**\n     * @param node\n     */\n    override fun logic(node: ASTNode) {\n        versionRegex ?: run {\n            versionRegex = KdocFormatConfiguration(\n                configRules.getRuleConfig(KDOC_CONTAINS_DATE_OR_AUTHOR)?.configuration ?: emptyMap()\n            )\n                .versionRegex\n        }\n\n        if (node.elementType == KDOC && isKdocNotEmpty(node)) {\n            checkNoDeprecatedTag(node)\n            checkEmptyTags(node.kDocTags())\n            checkSpaceAfterTag(node.kDocTags())\n            checkEmptyLineBeforeBasicTags(node.kDocBasicTags())\n            checkEmptyLinesBetweenBasicTags(node.kDocBasicTags())\n            checkBasicTagsOrder(node)\n            checkNewLineAfterSpecialTags(node)\n            checkAuthorAndDate(node)\n        }\n    }\n\n    private fun isKdocNotEmpty(node: ASTNode): Boolean {\n        val isKdocNotEmpty = node.getFirstChildWithType(KDocElementTypes.KDOC_SECTION)\n            ?.hasChildMatching {\n                it.elementType != KDocTokens.LEADING_ASTERISK && it.elementType != WHITE_SPACE\n            } ?: false\n        if (!isKdocNotEmpty) {\n            KDOC_EMPTY_KDOC.warn(configRules, emitWarn,\n                node.treeParent.getIdentifierName()?.text\n                    ?: node.nextSibling { it.elementType in KtTokens.KEYWORDS }?.text\n                    ?: node.text, node.startOffset, node)\n        }\n        return isKdocNotEmpty\n    }\n\n    @Suppress(\"UnsafeCallOnNullableType\")\n    private fun checkNoDeprecatedTag(node: ASTNode) {\n        val kdocTags = node.kDocTags()\n        kdocTags.find { it.name == \"deprecated\" }\n            ?.let { kdocTag ->\n                KDOC_NO_DEPRECATED_TAG.warnAndFix(configRules, emitWarn, isFixMode, kdocTag.text, kdocTag.node.startOffset, kdocTag.node) {\n                    val kdocSection = kdocTag.node.treeParent\n                    val deprecatedTagNode = kdocTag.node\n                    kdocSection.removeRange(deprecatedTagNode.prevSibling { it.elementType == WHITE_SPACE }!!,\n                        deprecatedTagNode.nextSibling { it.elementType == WHITE_SPACE }\n                    )\n                    node.treeParent.addChild(LeafPsiElement(KtNodeTypes.ANNOTATION,\n                        \"@Deprecated(message = \\\"${kdocTag.getContent()}\\\")\"), node.treeNext)\n                    // copy to get all necessary indents\n                    node.treeParent.addChild(node.nextSibling { it.elementType == WHITE_SPACE }!!.clone() as PsiWhiteSpaceImpl, node.treeNext)\n                }\n            }\n    }\n\n    @Suppress(\"UnsafeCallOnNullableType\")\n    private fun checkEmptyTags(kdocTags: Collection<KDocTag>?) {\n        kdocTags?.filter {\n            it.getSubjectName() == null && it.getContent().isEmpty()\n        }?.forEach {\n            KDOC_NO_EMPTY_TAGS.warn(configRules, emitWarn, \"@${it.name!!}\", it.node.startOffset, it.node)\n        }\n    }\n\n    @Suppress(\"UnsafeCallOnNullableType\")\n    private fun checkSpaceAfterTag(kdocTags: Collection<KDocTag>?) {\n        // tags can have 'parameters' and content, either can be missing\n        // we always can find white space after tag name, but after tag parameters only if content is present\n        kdocTags?.filter { tag ->\n            val hasSubject = tag.getSubjectName()?.isNotBlank() ?: false\n            if (!hasSubject && tag.getContent().isBlank()) {\n                return@filter false\n            }\n\n            val (isSpaceBeforeContentError, isSpaceAfterTagError) = findBeforeAndAfterSpaces(tag)\n\n            hasSubject && isSpaceBeforeContentError || isSpaceAfterTagError\n        }?.forEach { tag ->\n            KDOC_WRONG_SPACES_AFTER_TAG.warnAndFix(configRules, emitWarn, isFixMode,\n                \"@${tag.name!!}\", tag.node.startOffset, tag.node) {\n                tag.node.findChildBefore(KDocTokens.TEXT, WHITE_SPACE)\n                    ?.let { tag.node.replaceChild(it, LeafPsiElement(WHITE_SPACE, \" \")) }\n                tag.node.findChildAfter(KDocTokens.TAG_NAME, WHITE_SPACE)\n                    ?.let { tag.node.replaceChild(it, LeafPsiElement(WHITE_SPACE, \" \")) }\n            }\n        }\n    }\n\n    private fun findBeforeAndAfterSpaces(tag: KDocTag) = Pair(tag.node.findChildBefore(KDocTokens.TEXT, WHITE_SPACE).let {\n        it?.text != \" \" &&\n                !(it?.isWhiteSpaceWithNewline() ?: false)\n    },\n        tag.node.findChildAfter(KDocTokens.TAG_NAME, WHITE_SPACE).let {\n            it?.text != \" \" &&\n                    !(it?.isWhiteSpaceWithNewline() ?: false)\n        }\n    )\n\n    @Suppress(\"UnsafeCallOnNullableType\", \"TOO_LONG_FUNCTION\")\n    private fun checkBasicTagsOrder(node: ASTNode) {\n        val kdocTags = node.kDocTags()\n        // distinct basic tags which are present in current KDoc, in proper order\n        val basicTagsOrdered = basicTagsList.filter { basicTag ->\n            kdocTags.any { it.knownTag == basicTag }\n        }\n        // all basic tags from current KDoc\n        val basicTags = kdocTags.filter { basicTagsOrdered.contains(it.knownTag) }\n        val isTagsInCorrectOrder = basicTags\n            .fold(mutableListOf<KDocTag>()) { acc, kdocTag ->\n                if (acc.size > 0 && acc.last().knownTag != kdocTag.knownTag) {\n                    acc.add(kdocTag)\n                } else if (acc.size == 0) {\n                    acc.add(kdocTag)\n                }\n                acc\n            }\n            .map { it.knownTag } == basicTagsOrdered\n\n        if (!isTagsInCorrectOrder) {\n            KDOC_WRONG_TAGS_ORDER.warnAndFix(configRules, emitWarn, isFixMode,\n                basicTags.joinToString(\", \") { \"@${it.name}\" }, basicTags\n                    .first()\n                    .node\n                    .startOffset, basicTags.first().node) {\n                val basicTagChildren = kdocTags\n                    .filter { basicTagsOrdered.contains(it.knownTag) }\n                    .map { it.node }\n\n                val correctKdocOrder = basicTags\n                    .sortedBy { basicTagsOrdered.indexOf(it.knownTag) }\n                    .map { it.node }\n\n                basicTagChildren.mapIndexed { index, astNode ->\n                    val kdocSection = astNode.treeParent\n                    kdocSection.addChild(correctKdocOrder[index].clone() as CompositeElement, astNode)\n                    kdocSection.removeChild(astNode)\n                }\n            }\n        }\n    }\n\n    @Suppress(\"UnsafeCallOnNullableType\", \"TOO_LONG_FUNCTION\")\n    private fun checkEmptyLineBeforeBasicTags(basicTags: List<KDocTag>) {\n        val firstBasicTag = basicTags.firstOrNull() ?: return\n\n        val hasContentBefore = firstBasicTag\n            .node\n            .allSiblings(true)\n            .let { it.subList(0, it.indexOf(firstBasicTag.node)) }\n            .any { it.elementType !in arrayOf(WHITE_SPACE, KDocTokens.LEADING_ASTERISK) && it.text.isNotBlank() }\n\n        val previousTag = firstBasicTag.node.prevSibling { it.elementType == KDocElementTypes.KDOC_TAG }\n        val hasEmptyLineBefore = previousTag?.hasEmptyLineAfter()\n            ?: (firstBasicTag\n                .node\n                .previousAsterisk()\n                ?.previousAsterisk()\n                ?.treeNext\n                ?.elementType == WHITE_SPACE)\n\n        if (hasContentBefore xor hasEmptyLineBefore) {\n            KDOC_NEWLINES_BEFORE_BASIC_TAGS.warnAndFix(configRules, emitWarn, isFixMode,\n                \"@${firstBasicTag.name!!}\", firstBasicTag.node.startOffset, firstBasicTag.node) {\n                if (hasContentBefore) {\n                    previousTag?.applyToPrevSibling(KDocTokens.LEADING_ASTERISK) {\n                        previousTag.addChild(treePrev.clone() as ASTNode, null)\n                        previousTag.addChild(this.clone() as ASTNode, null)\n                    }\n                        ?: firstBasicTag.node.applyToPrevSibling(KDocTokens.LEADING_ASTERISK) {\n                            treeParent.addChild(treePrev.clone() as ASTNode, this)\n                            treeParent.addChild(this.clone() as ASTNode, treePrev)\n                        }\n                } else {\n                    firstBasicTag.node.apply {\n                        val asteriskNode = previousAsterisk()!!\n                        treeParent.removeChild(asteriskNode.treePrev)\n                        treeParent.removeChild(asteriskNode.treePrev)\n                    }\n                }\n            }\n        }\n    }\n\n    private fun checkEmptyLinesBetweenBasicTags(basicTags: List<KDocTag>) {\n        val tagsWithRedundantEmptyLines = basicTags.dropLast(1).filter { tag ->\n            val nextWhiteSpace = tag.node.nextSibling { it.elementType == WHITE_SPACE }\n            // either there is a trailing blank line in tag's body OR there are empty lines right after this tag\n            tag.hasTrailingNewlineInTagBody() || nextWhiteSpace?.text?.count { it == '\\n' } != 1\n        }\n\n        tagsWithRedundantEmptyLines.forEach { tag ->\n            KDOC_NO_NEWLINES_BETWEEN_BASIC_TAGS.warnAndFix(configRules, emitWarn, isFixMode,\n                \"@${tag.name}\", tag.startOffset, tag.node) {\n                if (tag.hasTrailingNewlineInTagBody()) {\n                    // if there is a blank line in tag's body, we remove it and everything after it, so that the next white space is kept in place\n                    // we look for the last LEADING_ASTERISK and take its previous node which should be WHITE_SPACE with newline\n                    tag.node.reversedChildren()\n                        .takeWhile { it.elementType == WHITE_SPACE || it.elementType == KDocTokens.LEADING_ASTERISK }\n                        .firstOrNull { it.elementType == KDocTokens.LEADING_ASTERISK }\n                        ?.let { tag.node.removeRange(it.treePrev, null) }\n                } else {\n                    // otherwise we remove redundant blank lines from white space node after tag\n                    tag.node.nextSibling { it.elementType == WHITE_SPACE }?.leaveOnlyOneNewLine()\n                }\n            }\n        }\n    }\n\n    @Suppress(\"UnsafeCallOnNullableType\", \"ComplexMethod\")\n    private fun checkNewLineAfterSpecialTags(node: ASTNode) {\n        val presentSpecialTagNodes = node\n            .getFirstChildWithType(KDocElementTypes.KDOC_SECTION)\n            ?.getAllChildrenWithType(KDocElementTypes.KDOC_TAG)\n            ?.filter { (it.psi as KDocTag).name in specialTagNames }\n\n        val poorlyFormattedTagNodes = presentSpecialTagNodes?.filterNot { specialTagNode ->\n            // empty line with just * followed by white space or end of block\n            specialTagNode.lastChildNode.elementType == KDocTokens.LEADING_ASTERISK &&\n                    (specialTagNode.treeNext == null || specialTagNode.treeNext.elementType == WHITE_SPACE &&\n                            specialTagNode.treeNext.text.count { it == '\\n' } == 1) &&\n                    // and with no empty line before\n                    specialTagNode.lastChildNode.treePrev.elementType == WHITE_SPACE &&\n                    specialTagNode.lastChildNode.treePrev.treePrev.elementType != KDocTokens.LEADING_ASTERISK\n        }\n\n        if (poorlyFormattedTagNodes != null && poorlyFormattedTagNodes.isNotEmpty()) {\n            KDOC_NO_NEWLINE_AFTER_SPECIAL_TAGS.warnAndFix(configRules, emitWarn, isFixMode,\n                poorlyFormattedTagNodes.joinToString(\", \") { \"@${(it.psi as KDocTag).name!!}\" },\n                poorlyFormattedTagNodes.first().startOffset, node) {\n                poorlyFormattedTagNodes.forEach { node ->\n                    while (node.lastChildNode.elementType == KDocTokens.LEADING_ASTERISK && node.lastChildNode.treePrev.treePrev.elementType == KDocTokens.LEADING_ASTERISK) {\n                        node.removeChild(node.lastChildNode)  // KDOC_LEADING_ASTERISK\n                        node.removeChild(node.lastChildNode)  // WHITE_SPACE\n                    }\n                    if (node.treeParent.lastChildNode != node && node.lastChildNode.elementType != KDocTokens.LEADING_ASTERISK) {\n                        val indent = node\n                            .prevSibling { it.elementType == WHITE_SPACE }\n                            ?.text\n                            ?.substringAfter('\\n')\n                            ?.count { it == ' ' } ?: 0\n                        node.addChild(PsiWhiteSpaceImpl(\"\\n${\" \".repeat(indent)}\"), null)\n                        node.addChild(LeafPsiElement(KDocTokens.LEADING_ASTERISK, \"*\"), null)\n                    }\n                }\n            }\n        }\n    }\n\n    private fun checkAuthorAndDate(node: ASTNode) {\n        node.kDocTags()\n            .filter {\n                it.knownTag == KDocKnownTag.AUTHOR ||\n                        it.knownTag == KDocKnownTag.SINCE && it.hasInvalidVersion()\n            }\n            .forEach {\n                KDOC_CONTAINS_DATE_OR_AUTHOR.warn(configRules, emitWarn, it.text.trim(), it.startOffset, it.node)\n            }\n    }\n\n    // fixme this method can be improved and extracted to utils\n    private fun ASTNode.hasEmptyLineAfter(): Boolean {\n        require(this.elementType == KDocElementTypes.KDOC_TAG) { \"This check is only for KDOC_TAG\" }\n        return lastChildNode.elementType == KDocTokens.LEADING_ASTERISK &&\n                (treeNext == null || treeNext.elementType == WHITE_SPACE && treeNext.text.count { it == '\\n' } == 1)\n    }\n\n    private fun ASTNode.kDocBasicTags() = kDocTags().filter { basicTagsList.contains(it.knownTag) }\n\n    private fun ASTNode.previousAsterisk() = prevSibling { it.elementType == KDocTokens.LEADING_ASTERISK }\n\n    private fun ASTNode.applyToPrevSibling(elementType: IElementType, consumer: ASTNode.() -> Unit) {\n        prevSibling { it.elementType == elementType }?.apply(consumer)\n    }\n\n    /**\n     * Checks whether this tag's content represents an invalid version\n     */\n    private fun KDocTag.hasInvalidVersion(): Boolean {\n        val content = getContent().trim()\n        if (' ' in content || '/' in content) {\n            // Filter based on symbols that are not allowed in versions. Assuming that people put either version or date in `@since` tag.\n            return true\n        }\n        return versionRegex?.matches(content)?.not()\n            ?: dateFormats.mapNotNull {\n                // try to parse using some standard date patterns\n                runCatching {\n                    it.parse(content).get(ChronoField.YEAR)\n                }\n                    .getOrNull()\n            }\n                .isNotEmpty()\n    }\n\n    /**\n     * A [RuleConfiguration] for KDoc formatting\n     */\n    class KdocFormatConfiguration(config: Map<String, String>) : RuleConfiguration(config) {\n        /**\n         * Regular expression, if present, against which a version should be matched in `@since` tag.\n         */\n        val versionRegex: Regex? by lazy {\n            config[\"versionRegex\"]?.let { Regex(it) }\n        }\n    }\n\n    companion object {\n        const val NAME_ID = \"kdoc-formatting\"\n        val dateFormats: List<DateTimeFormatter> = listOf(\"yyyy-dd-mm\", \"yy-dd-mm\", \"yyyy-mm-dd\", \"yy-mm-dd\", \"yyyy.mm.dd\", \"yyyy.dd.mm\")\n            .map {\n                DateTimeFormatter.ofPattern(it)\n            }\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/main/kotlin/com/saveourtool/diktat/ruleset/rules/chapter2/kdoc/KdocMethods.kt",
    "content": "package com.saveourtool.diktat.ruleset.rules.chapter2.kdoc\n\nimport com.saveourtool.diktat.common.config.rules.RulesConfig\nimport com.saveourtool.diktat.common.config.rules.getCommonConfiguration\nimport com.saveourtool.diktat.ruleset.constants.Warnings.KDOC_TRIVIAL_KDOC_ON_FUNCTION\nimport com.saveourtool.diktat.ruleset.constants.Warnings.KDOC_WITHOUT_PARAM_TAG\nimport com.saveourtool.diktat.ruleset.constants.Warnings.KDOC_WITHOUT_RETURN_TAG\nimport com.saveourtool.diktat.ruleset.constants.Warnings.KDOC_WITHOUT_THROWS_TAG\nimport com.saveourtool.diktat.ruleset.constants.Warnings.MISSING_KDOC_ON_FUNCTION\nimport com.saveourtool.diktat.ruleset.rules.DiktatRule\nimport com.saveourtool.diktat.ruleset.utils.KotlinParser\nimport com.saveourtool.diktat.ruleset.utils.appendNewlineMergingWhiteSpace\nimport com.saveourtool.diktat.ruleset.utils.findAllDescendantsWithSpecificType\nimport com.saveourtool.diktat.ruleset.utils.findChildAfter\nimport com.saveourtool.diktat.ruleset.utils.findParentNodeWithSpecificType\nimport com.saveourtool.diktat.ruleset.utils.getAllChildrenWithType\nimport com.saveourtool.diktat.ruleset.utils.getBodyLines\nimport com.saveourtool.diktat.ruleset.utils.getFilePath\nimport com.saveourtool.diktat.ruleset.utils.getFirstChildWithType\nimport com.saveourtool.diktat.ruleset.utils.getIdentifierName\nimport com.saveourtool.diktat.ruleset.utils.hasChildOfType\nimport com.saveourtool.diktat.ruleset.utils.hasKnownKdocTag\nimport com.saveourtool.diktat.ruleset.utils.hasTestAnnotation\nimport com.saveourtool.diktat.ruleset.utils.insertTagBefore\nimport com.saveourtool.diktat.ruleset.utils.isAccessibleOutside\nimport com.saveourtool.diktat.ruleset.utils.isAnonymousFunction\nimport com.saveourtool.diktat.ruleset.utils.isGetterOrSetter\nimport com.saveourtool.diktat.ruleset.utils.isLocatedInTest\nimport com.saveourtool.diktat.ruleset.utils.isOverridden\nimport com.saveourtool.diktat.ruleset.utils.isStandardMethod\nimport com.saveourtool.diktat.ruleset.utils.kDocTags\nimport com.saveourtool.diktat.ruleset.utils.parameterNames\nimport com.saveourtool.diktat.ruleset.utils.splitPathToDirs\n\nimport org.jetbrains.kotlin.KtNodeTypes\nimport org.jetbrains.kotlin.KtNodeTypes.BLOCK\nimport org.jetbrains.kotlin.KtNodeTypes.CALL_EXPRESSION\nimport org.jetbrains.kotlin.KtNodeTypes.CATCH\nimport org.jetbrains.kotlin.KtNodeTypes.DOT_QUALIFIED_EXPRESSION\nimport org.jetbrains.kotlin.KtNodeTypes.FUN\nimport org.jetbrains.kotlin.KtNodeTypes.MODIFIER_LIST\nimport org.jetbrains.kotlin.KtNodeTypes.REFERENCE_EXPRESSION\nimport org.jetbrains.kotlin.KtNodeTypes.THIS_EXPRESSION\nimport org.jetbrains.kotlin.KtNodeTypes.THROW\nimport org.jetbrains.kotlin.KtNodeTypes.TRY\nimport org.jetbrains.kotlin.KtNodeTypes.TYPE_REFERENCE\nimport org.jetbrains.kotlin.com.intellij.lang.ASTFactory\nimport org.jetbrains.kotlin.com.intellij.lang.ASTNode\nimport org.jetbrains.kotlin.com.intellij.psi.impl.source.tree.LeafPsiElement\nimport org.jetbrains.kotlin.com.intellij.psi.impl.source.tree.PsiWhiteSpaceImpl\nimport org.jetbrains.kotlin.com.intellij.psi.tree.TokenSet\nimport org.jetbrains.kotlin.kdoc.lexer.KDocTokens\nimport org.jetbrains.kotlin.kdoc.lexer.KDocTokens.KDOC\nimport org.jetbrains.kotlin.kdoc.parser.KDocElementTypes\nimport org.jetbrains.kotlin.kdoc.parser.KDocKnownTag\nimport org.jetbrains.kotlin.kdoc.psi.impl.KDocTag\nimport org.jetbrains.kotlin.lexer.KtTokens\nimport org.jetbrains.kotlin.lexer.KtTokens.COLON\nimport org.jetbrains.kotlin.lexer.KtTokens.EQ\nimport org.jetbrains.kotlin.lexer.KtTokens.IDENTIFIER\nimport org.jetbrains.kotlin.lexer.KtTokens.WHITE_SPACE\nimport org.jetbrains.kotlin.psi.KtCallExpression\nimport org.jetbrains.kotlin.psi.KtCatchClause\nimport org.jetbrains.kotlin.psi.KtDotQualifiedExpression\nimport org.jetbrains.kotlin.psi.KtFunction\nimport org.jetbrains.kotlin.psi.KtThrowExpression\nimport org.jetbrains.kotlin.psi.psiUtil.collectDescendantsOfType\nimport org.jetbrains.kotlin.psi.psiUtil.referenceExpression\nimport java.lang.Class.forName\n\n/**\n * This rule checks that whenever the method has arguments, return value, can throw exceptions,\n * KDoc block should contain `@param`, `@return`, `@throws`.\n * For `@return` check methods with explicit return type are supported and methods with inferred return\n * type are supported the following way: they should either declare return type `Unit` or have `@return` tag.\n * Currently only `throw` keyword from this methods body is supported for `@throws` check.\n */\n@Suppress(\"ForbiddenComment\")\nclass KdocMethods(configRules: List<RulesConfig>) : DiktatRule(\n    NAME_ID,\n    configRules,\n    listOf(KDOC_TRIVIAL_KDOC_ON_FUNCTION, KDOC_WITHOUT_PARAM_TAG, KDOC_WITHOUT_RETURN_TAG,\n        KDOC_WITHOUT_THROWS_TAG, MISSING_KDOC_ON_FUNCTION)\n) {\n    /**\n     * @param node\n     */\n    override fun logic(node: ASTNode) {\n        val isModifierAccessibleOutsideOrActual: Boolean by lazy {\n            node.getFirstChildWithType(MODIFIER_LIST).run {\n                isAccessibleOutside() && this?.hasChildOfType(KtTokens.ACTUAL_KEYWORD) != true\n            }\n        }\n        if (node.elementType == FUN && isModifierAccessibleOutsideOrActual && !node.isOverridden()) {\n            val config = configRules.getCommonConfiguration()\n            val filePath = node.getFilePath()\n            val isTestMethod = node.hasTestAnnotation() || isLocatedInTest(filePath.splitPathToDirs(), config.testAnchors)\n            if (!isTestMethod && !node.isStandardMethod() && !node.isSingleLineGetterOrSetter() && !node.isAnonymousFunction()) {\n                checkSignatureDescription(node)\n            }\n        } else if (node.elementType == KDocElementTypes.KDOC_SECTION) {\n            checkKdocBody(node)\n        }\n    }\n\n    private fun hasFunParent(node: ASTNode): Boolean {\n        var parent = node.treeParent\n        while (parent != null) {\n            if (parent.elementType == FUN) {\n                return true\n            }\n            parent = parent.treeParent\n        }\n        return false\n    }\n\n    @Suppress(\n        \"UnsafeCallOnNullableType\",\n        \"AVOID_NULL_CHECKS\",\n        \"CyclomaticComplexMethod\"\n    )\n    private fun checkSignatureDescription(node: ASTNode) {\n        val kdoc = node.getFirstChildWithType(KDOC)\n        val kdocTags = kdoc?.kDocTags()\n        val name = node.getIdentifierName()!!.text\n\n        val (missingParameters, kDocMissingParameters) = getMissingParameters(node, kdocTags)\n\n        val explicitlyThrownExceptions = getExplicitlyThrownExceptions(node) + getRethrownExceptions(node)\n        val missingExceptions = explicitlyThrownExceptions\n            .minus((kdocTags\n                ?.filter { it.knownTag == KDocKnownTag.THROWS }\n                ?.mapNotNull { it.getSubjectLinkName() }\n                ?.toSet() ?: emptySet()).toSet())\n\n        val paramCheckFailed = (missingParameters.isNotEmpty() && !node.isSingleLineGetterOrSetter()) || kDocMissingParameters.isNotEmpty()\n        val returnCheckFailed = hasReturnCheckFailed(node, kdocTags)\n        val throwsCheckFailed = missingExceptions.isNotEmpty()\n\n        val anyTagFailed = paramCheckFailed || returnCheckFailed || throwsCheckFailed\n        // if no tag failed, we have too little information to suggest KDoc - it would just be empty\n        if (kdoc == null && hasFunParent(node)) {\n            return\n        } else if (kdoc == null && anyTagFailed) {\n            addKdocTemplate(node, name, missingParameters, explicitlyThrownExceptions, returnCheckFailed)\n        } else if (kdoc == null && !isReferenceExpressionWithSameName(node)) {\n            MISSING_KDOC_ON_FUNCTION.warn(configRules, emitWarn, name, node.startOffset, node)\n        } else {\n            if (paramCheckFailed) {\n                handleParamCheck(node, kdoc, missingParameters, kDocMissingParameters, kdocTags)\n            }\n            if (returnCheckFailed) {\n                handleReturnCheck(node, kdoc, kdocTags)\n            }\n            if (throwsCheckFailed) {\n                handleThrowsCheck(node, kdoc, missingExceptions)\n            }\n        }\n    }\n\n    private fun KDocTag.getSubjectLinkName(): String? =\n        node.getChildren(null)\n            .dropWhile { it.elementType == KDocTokens.TAG_NAME }\n            .dropWhile { it.elementType == WHITE_SPACE }\n            .firstOrNull { it.elementType == KDocTokens.MARKDOWN_LINK }\n            ?.text\n\n    @Suppress(\"TYPE_ALIAS\")\n    private fun getMissingParameters(node: ASTNode, kdocTags: Collection<KDocTag>?): Pair<List<String?>, List<KDocTag>> {\n        val parameterNames = node.parameterNames()\n        val kdocParamList = kdocTags?.filter { it.knownTag == KDocKnownTag.PARAM && it.getSubjectLinkName() != null }\n        return if (parameterNames.isEmpty()) {\n            Pair(emptyList(), kdocParamList ?: emptyList())\n        } else if (!kdocParamList.isNullOrEmpty()) {\n            Pair(parameterNames.minus(kdocParamList.map { it.getSubjectLinkName() }.toSet()), kdocParamList.filter { it.getSubjectLinkName() !in parameterNames })\n        } else {\n            Pair(parameterNames.toList(), emptyList())\n        }\n    }\n\n    private fun isReferenceExpressionWithSameName(node: ASTNode): Boolean {\n        val lastDotQualifiedExpression = node.findChildByType(DOT_QUALIFIED_EXPRESSION)?.psi\n            ?.let { (it as KtDotQualifiedExpression).selectorExpression?.text?.substringBefore('(') }\n        val funName = (node.psi as KtFunction).name\n        return funName == lastDotQualifiedExpression\n    }\n\n    @Suppress(\"WRONG_NEWLINES\")\n    private fun hasReturnCheckFailed(node: ASTNode, kdocTags: Collection<KDocTag>?): Boolean {\n        if (node.isSingleLineGetterOrSetter()) {\n            return false\n        }\n\n        val explicitReturnType = node.findChildAfter(COLON, TYPE_REFERENCE)\n        val hasNotExpressionBodyTypes = allExpressionBodyTypes.any { node.hasChildOfType(it) }\n        val hasExplicitNotUnitReturnType = explicitReturnType != null && explicitReturnType.text != \"Unit\"\n        val hasExplicitUnitReturnType = explicitReturnType != null && explicitReturnType.text == \"Unit\"\n        val isFunWithExpressionBody = node.hasChildOfType(EQ)\n        val isReferenceExpressionWithSameName = node.findAllDescendantsWithSpecificType(REFERENCE_EXPRESSION).map { it.text }.contains((node.psi as KtFunction).name)\n        val hasReturnKdoc = kdocTags != null && kdocTags.hasKnownKdocTag(KDocKnownTag.RETURN)\n        return (hasExplicitNotUnitReturnType || isFunWithExpressionBody && !hasExplicitUnitReturnType && hasNotExpressionBodyTypes)\n                && !hasReturnKdoc && !isReferenceExpressionWithSameName\n    }\n\n    private fun isThrowInTryCatchBlock(node: ASTNode?): Boolean {\n        node ?: return false\n        val parent = node.findParentNodeWithSpecificType(TRY)\n        val nodeName = node.findAllDescendantsWithSpecificType(IDENTIFIER).firstOrNull() ?: return false\n\n        if (parent?.elementType == TRY) {\n            val catchNodes = parent?.getAllChildrenWithType(CATCH)\n            val findNodeWithMatchingCatch = catchNodes?.firstOrNull { catchNode ->\n                val matchingNodeForCatchNode = catchNode.findAllDescendantsWithSpecificType(IDENTIFIER)\n                    .firstOrNull { catchNodeName ->\n                        nodeName.text == catchNodeName.text || try {\n                            val nodeClass = forName(\"java.lang.${nodeName.text}\")\n                            val nodeInstance = nodeClass.getDeclaredConstructor().newInstance()\n                            val catchNodeClass = forName(\"java.lang.${catchNodeName.text}\")\n                            catchNodeClass.isInstance(nodeInstance)\n                        } catch (e: ClassNotFoundException) {\n                            false\n                        }\n                    }\n                matchingNodeForCatchNode != null\n            }\n            return findNodeWithMatchingCatch != null\n        }\n        return false\n    }\n\n    private fun getExplicitlyThrownExceptions(node: ASTNode): Set<String> {\n        val codeBlock = node.getFirstChildWithType(BLOCK)\n        val throwKeywords = codeBlock?.findAllDescendantsWithSpecificType(THROW)\n\n        return throwKeywords\n            ?.asSequence()\n            ?.filter { !isThrowInTryCatchBlock(it) }\n            ?.map { it.psi as KtThrowExpression }\n            ?.filter {\n                // we only take freshly created exceptions here: `throw IAE(\"stuff\")` vs `throw e`\n                it.thrownExpression is KtCallExpression\n            }\n            ?.mapNotNull { it.thrownExpression?.referenceExpression()?.text }\n            ?.toSet()\n            ?: emptySet()\n    }\n\n    @Suppress(\"UnsafeCallOnNullableType\")\n    private fun getRethrownExceptions(node: ASTNode) = node.findAllDescendantsWithSpecificType(CATCH).flatMap { catchClauseNode ->\n        // `parameterList` is `@Nullable @IfNotParsed`\n        (catchClauseNode.psi as KtCatchClause).parameterList!!.parameters\n            .filter {\n                // `catch (_: Exception)` - parameter can be anonymous\n                it.name != \"_\"\n            }\n            .filter { param ->\n                // check whether caught parameter is rethrown in the same catch clause\n                (catchClauseNode.psi as KtCatchClause).catchBody?.collectDescendantsOfType<KtThrowExpression>()?.any {\n                    it.thrownExpression?.referenceExpression()?.text == param.name\n                } == true\n            }\n            .map {\n                // parameter in catch statement `catch (e: Type)` should always have type\n                it.typeReference!!.text\n            }\n    }\n        .toSet()\n\n    @Suppress(\"UnsafeCallOnNullableType\")\n    private fun handleParamCheck(node: ASTNode,\n                                 kdoc: ASTNode?,\n                                 missingParameters: Collection<String?>,\n                                 kdocMissingParameters: List<KDocTag>,\n                                 kdocTags: Collection<KDocTag>?\n    ) {\n        kdocMissingParameters.forEach {\n            KDOC_WITHOUT_PARAM_TAG.warn(configRules, emitWarn,\n                \"${ it.getSubjectLinkName() } param isn't present in argument list\", it.node.startOffset,\n                it.node)\n        }\n        if (missingParameters.isNotEmpty()) {\n            KDOC_WITHOUT_PARAM_TAG.warnAndFix(configRules, emitWarn, isFixMode,\n                \"${node.getIdentifierName()!!.text} (${missingParameters.joinToString()})\", node.startOffset, node) {\n                val beforeTag = kdocTags?.find { it.knownTag == KDocKnownTag.RETURN }\n                    ?: kdocTags?.find { it.knownTag == KDocKnownTag.THROWS }\n                missingParameters.filterNotNull().forEach { missingParameter ->\n                    kdoc?.insertTagBefore(beforeTag?.node) {\n                        addChild(ASTFactory.leaf(KDocTokens.TAG_NAME, \"@param\"))\n                        addChild(ASTFactory.whitespace(\" \"))\n                        val kdocMarkdownLink = ASTFactory.composite(KDocTokens.MARKDOWN_LINK)\n                            .also { addChild(it) }\n                        val kdocName = ASTFactory.composite(KDocElementTypes.KDOC_NAME)\n                            .also { kdocMarkdownLink.addChild(it) }\n                        kdocName.addChild(ASTFactory.leaf(KtTokens.IDENTIFIER, missingParameter))\n                    }\n                }\n            }\n        }\n    }\n\n    @Suppress(\"UnsafeCallOnNullableType\")\n    private fun handleReturnCheck(node: ASTNode,\n                                  kdoc: ASTNode?,\n                                  kdocTags: Collection<KDocTag>?,\n    ) {\n        KDOC_WITHOUT_RETURN_TAG.warnAndFix(configRules, emitWarn, isFixMode, node.getIdentifierName()!!.text,\n            node.startOffset, node) {\n            val beforeTag = kdocTags?.find { it.knownTag == KDocKnownTag.THROWS }\n            kdoc?.insertTagBefore(beforeTag?.node) {\n                addChild(LeafPsiElement(KDocTokens.TAG_NAME, \"@return\"))\n            }\n        }\n    }\n\n    @Suppress(\"UnsafeCallOnNullableType\")\n    private fun handleThrowsCheck(node: ASTNode,\n                                  kdoc: ASTNode?,\n                                  missingExceptions: Collection<String>,\n    ) {\n        KDOC_WITHOUT_THROWS_TAG.warnAndFix(configRules, emitWarn, isFixMode,\n            \"${node.getIdentifierName()!!.text} (${missingExceptions.joinToString()})\", node.startOffset, node) {\n            missingExceptions.forEach {\n                kdoc?.insertTagBefore(null) {\n                    addChild(LeafPsiElement(KDocTokens.TAG_NAME, \"@throws\"))\n                    addChild(PsiWhiteSpaceImpl(\" \"))\n                    addChild(LeafPsiElement(KDocTokens.MARKDOWN_LINK, it))\n                }\n            }\n        }\n    }\n\n    @Suppress(\"UnsafeCallOnNullableType\")\n    private fun addKdocTemplate(node: ASTNode,\n                                name: String,\n                                missingParameters: Collection<String?>,\n                                explicitlyThrownExceptions: Collection<String>,\n                                returnCheckFailed: Boolean,\n    ) {\n        MISSING_KDOC_ON_FUNCTION.warnAndFix(configRules, emitWarn, isFixMode, name, node.startOffset, node) {\n            val kdocTemplate = \"/**\\n\" +\n                    (missingParameters.joinToString(\"\") { \" * @param $it\\n\" } +\n                            (if (returnCheckFailed) \" * @return\\n\" else \"\") +\n                            explicitlyThrownExceptions.joinToString(\"\") { \" * @throws $it\\n\" } +\n                            \" */\\n\"\n                    )\n            val kdocNode = KotlinParser().createNode(kdocTemplate).findChildByType(KDOC)!!\n            node.appendNewlineMergingWhiteSpace(node.firstChildNode, node.firstChildNode)\n            node.addChild(kdocNode, node.firstChildNode)\n        }\n    }\n\n    private fun checkKdocBody(node: ASTNode) {\n        val kdocTextNodes = node.getChildren(TokenSet.create(KDocTokens.TEXT))\n        if (kdocTextNodes.size == 1) {\n            val kdocText = kdocTextNodes\n                .first()\n                .text\n                .trim()\n            if (kdocText.matches(uselessKdocRegex)) {\n                KDOC_TRIVIAL_KDOC_ON_FUNCTION.warn(configRules, emitWarn, kdocText, kdocTextNodes.first().startOffset, node)\n            }\n        }\n    }\n\n    private fun ASTNode.isSingleLineGetterOrSetter(): Boolean {\n        val dotQualifiedExp = this.findChildByType(DOT_QUALIFIED_EXPRESSION)?.psi?.let { it as KtDotQualifiedExpression }\n        val isThisExpression = dotQualifiedExp != null && dotQualifiedExp.receiverExpression.node.elementType == THIS_EXPRESSION\n        val isExpressionBodyTypes = expressionBodyTypes.any { hasChildOfType(it) }\n        return isGetterOrSetter() && (isExpressionBodyTypes || getBodyLines().size == 1 || isThisExpression)\n    }\n\n    companion object {\n        const val NAME_ID = \"kdoc-methods\"\n        private val expressionBodyTypes = setOf(CALL_EXPRESSION, REFERENCE_EXPRESSION)\n        private val allExpressionBodyTypes = setOf(\n            DOT_QUALIFIED_EXPRESSION,\n            CALL_EXPRESSION,\n            REFERENCE_EXPRESSION,\n            KtNodeTypes.BINARY_EXPRESSION,\n            KtNodeTypes.LAMBDA_EXPRESSION,\n            KtNodeTypes.CALLABLE_REFERENCE_EXPRESSION,\n            KtNodeTypes.SAFE_ACCESS_EXPRESSION,\n            KtNodeTypes.WHEN_CONDITION_EXPRESSION,\n            KtNodeTypes.COLLECTION_LITERAL_EXPRESSION,\n        )\n        private val uselessKdocRegex = \"\"\"^([rR]eturn|[gGsS]et)[s]?\\s+\\w+(\\s+\\w+)?$\"\"\".toRegex()\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/main/kotlin/com/saveourtool/diktat/ruleset/rules/chapter3/AnnotationNewLineRule.kt",
    "content": "package com.saveourtool.diktat.ruleset.rules.chapter3\n\nimport com.saveourtool.diktat.common.config.rules.RulesConfig\nimport com.saveourtool.diktat.ruleset.constants.Warnings.ANNOTATION_NEW_LINE\nimport com.saveourtool.diktat.ruleset.rules.DiktatRule\nimport com.saveourtool.diktat.ruleset.utils.*\n\nimport org.jetbrains.kotlin.KtNodeTypes.ANNOTATION_ENTRY\nimport org.jetbrains.kotlin.KtNodeTypes.CLASS\nimport org.jetbrains.kotlin.KtNodeTypes.FUN\nimport org.jetbrains.kotlin.KtNodeTypes.MODIFIER_LIST\nimport org.jetbrains.kotlin.KtNodeTypes.PRIMARY_CONSTRUCTOR\nimport org.jetbrains.kotlin.KtNodeTypes.SECONDARY_CONSTRUCTOR\nimport org.jetbrains.kotlin.com.intellij.lang.ASTNode\nimport org.jetbrains.kotlin.com.intellij.psi.impl.source.tree.LeafPsiElement\nimport org.jetbrains.kotlin.com.intellij.psi.impl.source.tree.PsiWhiteSpaceImpl\n\n/**\n * This rule makes each annotation applied to a class, method or constructor is on its own line. Except: if first annotation of constructor, class or method\n */\nclass AnnotationNewLineRule(configRules: List<RulesConfig>) : DiktatRule(\n    NAME_ID,\n    configRules,\n    listOf(ANNOTATION_NEW_LINE)\n) {\n    override fun logic(node: ASTNode) {\n        when (node.elementType) {\n            CLASS, FUN, PRIMARY_CONSTRUCTOR, SECONDARY_CONSTRUCTOR -> checkAnnotation(node)\n            else -> return\n        }\n    }\n\n    private fun checkAnnotation(node: ASTNode) {\n        node.findChildByType(MODIFIER_LIST)?.let { modList ->\n            fixAnnotation(modList)\n        }\n    }\n\n    private fun fixAnnotation(node: ASTNode) {\n        if (node.getAllChildrenWithType(ANNOTATION_ENTRY).size <= 1) {\n            return\n        }\n\n        node.getAllChildrenWithType(ANNOTATION_ENTRY).forEach {\n            if (!it.isFollowedByNewlineWithComment() || !it.isBeginNewLineWithComment()) {\n                deleteSpaces(it, !it.isFollowedByNewlineWithComment())\n            }\n        }\n    }\n\n    private fun deleteSpaces(node: ASTNode,\n                             rightSide: Boolean) {\n        ANNOTATION_NEW_LINE.warnAndFix(configRules, emitWarn, isFixMode, \"${node.text} not on a single line\",\n            node.startOffset, node) {\n            if (rightSide) {\n                if (node.treeNext?.isWhiteSpace() == true) {\n                    node.removeChild(node.treeNext)\n                }\n                node.treeParent.addChild(PsiWhiteSpaceImpl(\"\\n\"), node.treeNext)\n            }\n\n            if (node == node.treeParent.getFirstChildWithType(node.elementType)) {\n                // Current node is ANNOTATION_ENTRY. treeParent(ModifierList) -> treeParent(PRIMARY_CONSTRUCTOR)\n                // Checks if there is a white space before grandparent node\n                val hasSpaceBeforeGrandparent = node\n                    .treeParent\n                    .treeParent\n                    .treePrev\n                    .isWhiteSpace()\n                if (hasSpaceBeforeGrandparent) {\n                    (node.treeParent.treeParent.treePrev as LeafPsiElement).rawReplaceWithText(\"\\n\")\n                }\n            }\n        }\n    }\n\n    companion object {\n        const val NAME_ID = \"annotation-new-line\"\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/main/kotlin/com/saveourtool/diktat/ruleset/rules/chapter3/BlockStructureBraces.kt",
    "content": "package com.saveourtool.diktat.ruleset.rules.chapter3\n\nimport com.saveourtool.diktat.common.config.rules.RuleConfiguration\nimport com.saveourtool.diktat.common.config.rules.RulesConfig\nimport com.saveourtool.diktat.common.config.rules.getRuleConfig\nimport com.saveourtool.diktat.ruleset.constants.Warnings.BRACES_BLOCK_STRUCTURE_ERROR\nimport com.saveourtool.diktat.ruleset.rules.DiktatRule\nimport com.saveourtool.diktat.ruleset.utils.*\nimport com.saveourtool.diktat.ruleset.utils.isWhiteSpaceWithNewline\n\nimport org.jetbrains.kotlin.KtNodeTypes.BLOCK\nimport org.jetbrains.kotlin.KtNodeTypes.BODY\nimport org.jetbrains.kotlin.KtNodeTypes.CATCH\nimport org.jetbrains.kotlin.KtNodeTypes.CLASS\nimport org.jetbrains.kotlin.KtNodeTypes.CLASS_BODY\nimport org.jetbrains.kotlin.KtNodeTypes.CLASS_INITIALIZER\nimport org.jetbrains.kotlin.KtNodeTypes.DO_WHILE\nimport org.jetbrains.kotlin.KtNodeTypes.ELSE\nimport org.jetbrains.kotlin.KtNodeTypes.FINALLY\nimport org.jetbrains.kotlin.KtNodeTypes.FUN\nimport org.jetbrains.kotlin.KtNodeTypes.FUNCTION_LITERAL\nimport org.jetbrains.kotlin.KtNodeTypes.IF\nimport org.jetbrains.kotlin.KtNodeTypes.LAMBDA_ARGUMENT\nimport org.jetbrains.kotlin.KtNodeTypes.OBJECT_DECLARATION\nimport org.jetbrains.kotlin.KtNodeTypes.SECONDARY_CONSTRUCTOR\nimport org.jetbrains.kotlin.KtNodeTypes.THEN\nimport org.jetbrains.kotlin.KtNodeTypes.TRY\nimport org.jetbrains.kotlin.KtNodeTypes.WHEN\nimport org.jetbrains.kotlin.com.intellij.lang.ASTNode\nimport org.jetbrains.kotlin.com.intellij.psi.impl.source.tree.LeafPsiElement\nimport org.jetbrains.kotlin.com.intellij.psi.impl.source.tree.PsiWhiteSpaceImpl\nimport org.jetbrains.kotlin.com.intellij.psi.tree.IElementType\nimport org.jetbrains.kotlin.lexer.KtTokens.CATCH_KEYWORD\nimport org.jetbrains.kotlin.lexer.KtTokens.ELSE_KEYWORD\nimport org.jetbrains.kotlin.lexer.KtTokens.FINALLY_KEYWORD\nimport org.jetbrains.kotlin.lexer.KtTokens.LBRACE\nimport org.jetbrains.kotlin.lexer.KtTokens.RBRACE\nimport org.jetbrains.kotlin.lexer.KtTokens.WHILE_KEYWORD\nimport org.jetbrains.kotlin.lexer.KtTokens.WHITE_SPACE\nimport org.jetbrains.kotlin.psi.KtIfExpression\nimport org.jetbrains.kotlin.psi.KtTryExpression\n\n/**\n * This rule checks that *non-empty* code blocks with braces follow the K&R style (1TBS or OTBS style):\n * - The opening brace is on the same same line with the first line of the code block\n * - The closing brace is on it's new line\n * - The closing brace can be followed by a new line. Only exceptions are: `else`, `finally`, `while` (from do-while statement) or `catch` keywords.\n *   These keywords should not be split from the closing brace by a newline.\n * Exceptions:\n * - opening brace of lambda\n * - braces around `else`/`catch`/`finally`/`while` (in `do-while` loop)\n */\nclass BlockStructureBraces(configRules: List<RulesConfig>) : DiktatRule(\n    NAME_ID,\n    configRules,\n    listOf(BRACES_BLOCK_STRUCTURE_ERROR),\n) {\n    override fun logic(node: ASTNode) {\n        val configuration = BlockStructureBracesConfiguration(\n            configRules.getRuleConfig(BRACES_BLOCK_STRUCTURE_ERROR)?.configuration ?: emptyMap()\n        )\n\n        when (node.elementType) {\n            FUNCTION_LITERAL -> checkLambda(node, configuration)\n            CLASS, OBJECT_DECLARATION -> checkClass(node, configuration)\n            FUN, CLASS_INITIALIZER, SECONDARY_CONSTRUCTOR -> checkFun(node, configuration)\n            IF -> checkIf(node, configuration)\n            WHEN -> checkWhen(node, configuration)\n            in loopType -> checkLoop(node, configuration)\n            TRY -> checkTry(node, configuration)\n            else -> return\n        }\n    }\n\n    private fun checkLambda(node: ASTNode, configuration: BlockStructureBracesConfiguration) {\n        val isSingleLineLambda = node.text.lines().size == 1\n        if (!isSingleLineLambda) {\n            checkCloseBrace(node, configuration)\n        }\n    }\n\n    @Suppress(\"UnsafeCallOnNullableType\")\n    private fun checkClass(node: ASTNode, configuration: BlockStructureBracesConfiguration) {\n        if (node.hasChildOfType(CLASS_BODY) && !node.findChildByType(CLASS_BODY).isBlockEmpty()) {\n            checkOpenBraceOnSameLine(node, CLASS_BODY, configuration)\n            checkCloseBrace(node.findChildByType(CLASS_BODY)!!, configuration)\n        }\n    }\n\n    @Suppress(\"UnsafeCallOnNullableType\")  // `catch` and `finally` clauses should always have body in `{}`, therefore !!\n    private fun checkTry(node: ASTNode, configuration: BlockStructureBracesConfiguration) {\n        val tryBlock = node.psi as KtTryExpression\n        val catchBlocks = tryBlock.catchClauses.map { it.node }\n        val finallyBlock = tryBlock.finallyBlock?.node\n        checkOpenBraceOnSameLine(tryBlock.node, BLOCK, configuration)\n        val allMiddleSpaceNodes = node.findAllDescendantsWithSpecificType(CATCH).map { it.treePrev }\n        checkMidBrace(allMiddleSpaceNodes, node, CATCH_KEYWORD)\n        catchBlocks.forEach {\n            checkOpenBraceOnSameLine(it, BLOCK, configuration)\n            checkCloseBrace(it.findChildByType(BLOCK)!!, configuration)\n        }\n        finallyBlock?.let { block ->\n            checkOpenBraceOnSameLine(block, BLOCK, configuration)\n            checkCloseBrace(block.findChildByType(BLOCK)!!, configuration)\n            val newAllMiddleSpaceNodes = node.findAllDescendantsWithSpecificType(FINALLY).map { it.treePrev }\n            checkMidBrace(newAllMiddleSpaceNodes, node, FINALLY_KEYWORD)\n        }\n    }\n\n    @Suppress(\"UnsafeCallOnNullableType\")\n    private fun checkLoop(node: ASTNode, configuration: BlockStructureBracesConfiguration) {\n        node.findChildByType(BODY)?.let {\n            if (!it.findChildByType(BLOCK).isBlockEmpty()) {\n                checkOpenBraceOnSameLine(node, BODY, configuration)\n                // check that there is a `BLOCK` child is done inside `!isBlockEmpty`\n                checkCloseBrace(it.findChildByType(BLOCK)!!, configuration)\n                if (node.elementType == DO_WHILE) {\n                    val allMiddleNode = listOf(node.findChildByType(BODY)!!.treeNext)\n                    checkMidBrace(allMiddleNode, node, WHILE_KEYWORD)\n                }\n            }\n        }\n    }\n\n    private fun checkWhen(node: ASTNode, configuration: BlockStructureBracesConfiguration) {\n        /// WHEN expression doesn't contain BLOCK element and LBRECE isn't the first child, so we should to find it.\n        val childrenAfterLbrace = node\n            .getChildren(null)\n            .toList()\n            .run { subList(indexOfFirst { it.elementType == LBRACE }, size) }\n        if (!emptyBlockList.containsAll(childrenAfterLbrace.distinct().map { it.elementType })) {\n            checkOpenBraceOnSameLine(node, LBRACE, configuration)\n            checkCloseBrace(node, configuration)\n        }\n    }\n\n    @Suppress(\"UnsafeCallOnNullableType\")\n    private fun checkFun(node: ASTNode, configuration: BlockStructureBracesConfiguration) {\n        if (!node.findChildByType(BLOCK).isBlockEmpty()) {\n            checkOpenBraceOnSameLine(node, BLOCK, configuration)\n            checkCloseBrace(node.findChildByType(BLOCK)!!, configuration)\n        }\n    }\n\n    @Suppress(\"UnsafeCallOnNullableType\")\n    private fun checkIf(node: ASTNode, configuration: BlockStructureBracesConfiguration) {\n        val ifPsi = node.psi as KtIfExpression\n        val thenNode = ifPsi.then?.node\n        val hasElseBranch = ifPsi.elseKeyword != null\n        val elseNode = ifPsi.`else`?.node\n        if (thenNode != null && thenNode.hasChildOfType(LBRACE)) {\n            checkOpenBraceOnSameLine(node, THEN, configuration)\n            checkCloseBrace(thenNode, configuration)\n            if (hasElseBranch) {\n                // thenNode might have been altered by this point\n                val allMiddleNode = listOf(node.findChildByType(THEN)!!.treeNext)\n                checkMidBrace(allMiddleNode, node, ELSE_KEYWORD)\n            }\n        }\n        if (hasElseBranch && elseNode != null && elseNode.elementType != IF && elseNode.hasChildOfType(LBRACE)) {\n            checkOpenBraceOnSameLine(node, ELSE, configuration)\n            checkCloseBrace(elseNode, configuration)\n        }\n    }\n\n    private fun checkOpenBraceOnSameLine(\n        node: ASTNode,\n        beforeType: IElementType,\n        configuration: BlockStructureBracesConfiguration\n    ) {\n        if (!configuration.openBrace) {\n            return\n        }\n        val nodeBefore = node.findChildByType(beforeType)\n        val braceSpace = nodeBefore?.treePrev\n        if (braceSpace == null || checkBraceNode(braceSpace, true)) {\n            BRACES_BLOCK_STRUCTURE_ERROR.warnAndFix(configRules, emitWarn, isFixMode, \"incorrect newline before opening brace\",\n                (braceSpace ?: node).startOffset, node) {\n                if (braceSpace == null || braceSpace.elementType != WHITE_SPACE) {\n                    node.addChild(PsiWhiteSpaceImpl(\" \"), nodeBefore)\n                } else {\n                    if (braceSpace.treePrev.elementType in commentType) {\n                        val commentBefore = braceSpace.treePrev\n                        if (commentBefore.treePrev.elementType == WHITE_SPACE) {\n                            commentBefore.treeParent.removeChild(commentBefore.treePrev)\n                        }\n                        commentBefore.treeParent.removeChild(commentBefore)\n                        node.treeParent.addChild(commentBefore.clone() as ASTNode, node)\n                        node.treeParent.addChild(PsiWhiteSpaceImpl(\"\\n\"), node)\n                    }\n                    braceSpace.treeParent.replaceWhiteSpaceText(braceSpace, \" \")\n                }\n            }\n        }\n        checkOpenBraceEndLine(node, beforeType)\n    }\n\n    private fun checkOpenBraceEndLine(node: ASTNode, beforeType: IElementType) {\n        val newNode = (if (beforeType == THEN || beforeType == ELSE) node.findChildByType(beforeType) else node)\n            ?.findLBrace()\n            ?.treeNext\n            ?: return\n        if (checkBraceNode(newNode)) {\n            BRACES_BLOCK_STRUCTURE_ERROR.warnAndFix(configRules, emitWarn, isFixMode, \"incorrect same line after opening brace\",\n                newNode.startOffset, newNode) {\n                if (newNode.elementType != WHITE_SPACE) {\n                    newNode.treeParent.addChild(PsiWhiteSpaceImpl(\"\\n\"), newNode)\n                } else {\n                    (newNode as LeafPsiElement).rawReplaceWithText(\"\\n\")\n                }\n            }\n        }\n    }\n\n    private fun checkMidBrace(\n        allMiddleSpace: List<ASTNode>,\n        node: ASTNode,\n        keyword: IElementType\n    ) {\n        allMiddleSpace.forEach { space ->\n            if (checkBraceNode(space, true)) {\n                BRACES_BLOCK_STRUCTURE_ERROR.warnAndFix(configRules, emitWarn, isFixMode, \"incorrect new line after closing brace\",\n                    space.startOffset, space) {\n                    if (space.elementType != WHITE_SPACE) {\n                        node.addChild(PsiWhiteSpaceImpl(\" \"), node.findChildByType(keyword))\n                    } else {\n                        (space as LeafPsiElement).rawReplaceWithText(\" \")\n                    }\n                }\n            }\n        }\n    }\n\n    @Suppress(\"UnsafeCallOnNullableType\")\n    private fun checkCloseBrace(node: ASTNode, configuration: BlockStructureBracesConfiguration) {\n        if (!configuration.closeBrace) {\n            return\n        }\n        val space = node.findChildByType(RBRACE)!!.treePrev\n        node.findParentNodeWithSpecificType(LAMBDA_ARGUMENT)?.let {\n            if (space.text.isEmpty()) {\n                return\n            }\n        }\n        if (checkBraceNode(space)) {\n            BRACES_BLOCK_STRUCTURE_ERROR.warnAndFix(configRules, emitWarn, isFixMode, \"no newline before closing brace\",\n                (space.treeNext ?: node.findChildByType(RBRACE))!!.startOffset, node) {\n                if (space.elementType != WHITE_SPACE) {\n                    node.addChild(PsiWhiteSpaceImpl(\"\\n\"), node.findChildByType(RBRACE))\n                } else {\n                    (space as LeafPsiElement).rawReplaceWithText(\"\\n\")\n                }\n            }\n        }\n    }\n\n    private fun checkBraceNode(node: ASTNode, shouldContainNewline: Boolean = false) =\n        shouldContainNewline == node.isWhiteSpaceWithNewline()\n\n    /**\n     * Configuration for style of braces in block\n     */\n    class BlockStructureBracesConfiguration(config: Map<String, String>) : RuleConfiguration(config) {\n        /**\n         * Whether the opening brace should be placed on a new line\n         */\n        val openBrace = config[\"openBraceNewline\"]?.toBoolean() ?: true\n\n        /**\n         * Whether a closing brace should be placed on a new line\n         */\n        val closeBrace = config[\"closeBraceNewline\"]?.toBoolean() ?: true\n    }\n\n    companion object {\n        const val NAME_ID = \"block-structure\"\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/main/kotlin/com/saveourtool/diktat/ruleset/rules/chapter3/BooleanExpressionsRule.kt",
    "content": "package com.saveourtool.diktat.ruleset.rules.chapter3\n\nimport com.saveourtool.diktat.common.config.rules.RulesConfig\nimport com.saveourtool.diktat.ruleset.constants.Warnings.COMPLEX_BOOLEAN_EXPRESSION\nimport com.saveourtool.diktat.ruleset.rules.DiktatRule\nimport com.saveourtool.diktat.ruleset.utils.KotlinParser\nimport com.saveourtool.diktat.ruleset.utils.findAllNodesWithCondition\nimport com.saveourtool.diktat.ruleset.utils.isLeaf\nimport com.saveourtool.diktat.ruleset.utils.isPartOfComment\nimport com.saveourtool.diktat.ruleset.utils.logicalInfixMethodMapping\nimport com.saveourtool.diktat.ruleset.utils.logicalInfixMethods\n\nimport com.bpodgursky.jbool_expressions.Expression\nimport com.bpodgursky.jbool_expressions.options.ExprOptions\nimport com.bpodgursky.jbool_expressions.parsers.ExprParser\nimport com.bpodgursky.jbool_expressions.parsers.TokenMapper\nimport com.bpodgursky.jbool_expressions.rules.DeMorgan\nimport com.bpodgursky.jbool_expressions.rules.DistributiveLaw\nimport com.bpodgursky.jbool_expressions.rules.Rule\nimport com.bpodgursky.jbool_expressions.rules.RuleList\nimport com.bpodgursky.jbool_expressions.rules.RulesHelper\nimport org.jetbrains.kotlin.KtNodeTypes.BINARY_EXPRESSION\nimport org.jetbrains.kotlin.KtNodeTypes.CONDITION\nimport org.jetbrains.kotlin.KtNodeTypes.PARENTHESIZED\nimport org.jetbrains.kotlin.KtNodeTypes.PREFIX_EXPRESSION\nimport org.jetbrains.kotlin.com.intellij.lang.ASTNode\nimport org.jetbrains.kotlin.psi.KtBinaryExpression\nimport org.jetbrains.kotlin.psi.KtParenthesizedExpression\nimport org.jetbrains.kotlin.psi.KtPrefixExpression\nimport org.jetbrains.kotlin.psi.psiUtil.parents\n\n/**\n * Rule that checks if the boolean expression can be simplified.\n */\nclass BooleanExpressionsRule(configRules: List<RulesConfig>) : DiktatRule(\n    NAME_ID,\n    configRules,\n    listOf(COMPLEX_BOOLEAN_EXPRESSION)\n) {\n    override fun logic(node: ASTNode) {\n        if (node.elementType == CONDITION) {\n            checkBooleanExpression(node)\n        }\n    }\n\n    @Suppress(\"TooGenericExceptionCaught\")\n    private fun checkBooleanExpression(node: ASTNode) {\n        // This class is used to assign a variable name for every elementary boolean expression. It is required for jbool to operate.\n        val expressionsReplacement = ExpressionsReplacement()\n        val correctedExpression = formatBooleanExpressionAsString(node, expressionsReplacement)\n        if (expressionsReplacement.isEmpty()) {\n            // this happens, if we haven't found any expressions that can be simplified\n            return\n        }\n\n        // If there are method calls in conditions\n        val expr: Expression<String> = try {\n            ExprParser.parse(correctedExpression, expressionsReplacement.orderedTokenMapper)\n        } catch (exc: RuntimeException) {\n            if (exc.message?.startsWith(\"Unrecognized!\") == true) {\n                // this comes up if there is an unparsable expression (jbool doesn't have own exception type). For example a.and(b)\n                return\n            } else {\n                throw exc\n            }\n        }\n        val simplifiedExpression = RulesHelper.applySet(expr, allRules(), ExprOptions.noCaching())\n        if (expr != simplifiedExpression) {\n            COMPLEX_BOOLEAN_EXPRESSION.warnAndFix(configRules, emitWarn, isFixMode, node.text, node.startOffset, node) {\n                fixBooleanExpression(node, simplifiedExpression, expressionsReplacement)\n            }\n        }\n    }\n\n    /**\n     * Converts a complex boolean expression into a string representation, mapping each elementary expression to a letter token.\n     * These tokens are collected into [expressionsReplacement].\n     * For example:\n     * ```\n     * (a > 5 && b != 2) -> A & B\n     * (a > 5 || false) -> A | false\n     * (a > 5 || x.foo()) -> A | B\n     * ```\n     *\n     * @param node\n     * @param expressionsReplacement a special class for replacements expression->token\n     * @return formatted string representation of expression\n     */\n    @Suppress(\"UnsafeCallOnNullableType\", \"ForbiddenComment\")\n    internal fun formatBooleanExpressionAsString(node: ASTNode, expressionsReplacement: ExpressionsReplacement): String {\n        val (booleanBinaryExpressions, otherBinaryExpressions) = node.collectElementaryExpressions()\n        val logicalExpressions = otherBinaryExpressions.filter { otherBinaryExpression ->\n            // keeping only boolean expressions, keeping things like `a + b < 6` and excluding `a + b`\n            (otherBinaryExpression.psi as KtBinaryExpression).operationReference.text in logicalInfixMethods &&\n                    // todo: support xor; for now skip all expressions that are nested in xor\n                    otherBinaryExpression.parents()\n                        .takeWhile { it != node }\n                        .none { (it.psi as? KtBinaryExpression)?.isXorExpression() ?: false }\n        }\n        // Boolean expressions like `a > 5 && b < 7` or `x.isEmpty() || (y.isNotEmpty())` we convert to individual parts.\n        val elementaryBooleanExpressions = booleanBinaryExpressions\n            .map { it.psi as KtBinaryExpression }\n            .flatMap { listOf(it.left!!.node, it.right!!.node) }\n            .map {\n                // remove parentheses around expression, if there are any\n                it.removeAllParentheses()\n            }\n            .filterNot {\n                // finally, if parts are binary expressions themselves, they should be present in our lists and we will process them later.\n                it.elementType == BINARY_EXPRESSION ||\n                        // !(a || b) should be skipped too, `a` and `b` should be present later\n                        (it.psi as? KtPrefixExpression)?.lastChild\n                            ?.node\n                            ?.removeAllParentheses()\n                            ?.elementType == BINARY_EXPRESSION ||\n                        // `true` and `false` are valid tokens for jBool, so we keep them.\n                        it.text == \"true\" || it.text == \"false\"\n            }\n        (logicalExpressions + elementaryBooleanExpressions).forEach { expression ->\n            expressionsReplacement.addExpression(expression)\n        }\n        // Prepare final formatted string\n        // At first, substitute all elementary expressions with variables\n        val correctedExpression = expressionsReplacement.replaceExpressions(node.textWithoutComments())\n        // jBool library is using & as && and | as ||\n        return \"(${correctedExpression\n            .replace(\"&&\", \"&\")\n            .replace(\"||\", \"|\")})\"\n    }\n\n    /**\n     * Split the complex expression into elementary parts\n     */\n    private fun ASTNode.collectElementaryExpressions() = this\n        .findAllNodesWithCondition { astNode ->\n            astNode.elementType == BINARY_EXPRESSION &&\n                    // filter out boolean conditions in nested lambdas, e.g. `if (foo.filter { a && b })`\n                    (astNode == this || astNode.parents().takeWhile { it != this }\n                        .all { it.elementType in setOf(BINARY_EXPRESSION, PARENTHESIZED, PREFIX_EXPRESSION) })\n        }\n        .partition {\n            val operationReferenceText = (it.psi as KtBinaryExpression).operationReference.text\n            operationReferenceText == \"&&\" || operationReferenceText == \"||\"\n        }\n\n    private fun ASTNode.removeAllParentheses(): ASTNode {\n        val result = (this.psi as? KtParenthesizedExpression)?.expression?.node ?: return this\n        return result.removeAllParentheses()\n    }\n\n    private fun ASTNode.textWithoutComments() = findAllNodesWithCondition(withSelf = false) {\n        it.isLeaf()\n    }\n        .filterNot { it.isPartOfComment() }\n        .joinToString(separator = \"\") { it.text }\n        .replace(\"\\n\", \" \")\n\n    private fun fixBooleanExpression(\n        node: ASTNode,\n        simplifiedExpr: Expression<String>,\n        expressionsReplacement: ExpressionsReplacement\n    ) {\n        val correctKotlinBooleanExpression = simplifiedExpr\n            .toString()\n            .replace(\"&\", \"&&\")\n            .replace(\"|\", \"||\")\n            .removePrefix(\"(\")\n            .removeSuffix(\")\")\n\n        node.replaceChild(node.firstChildNode,\n            KotlinParser().createNode(expressionsReplacement.restoreFullExpression(correctKotlinBooleanExpression)))\n    }\n\n    private fun KtBinaryExpression.isXorExpression() = operationReference.text == \"xor\"\n\n    /**\n     * A special class to replace expressions (and restore it back)\n     * Note: mapping is String to Char(and Char to Char) actually, but will keep it as String for simplicity\n     */\n    internal inner class ExpressionsReplacement {\n        private val expressionToToken: HashMap<String, String> = LinkedHashMap()\n        private val tokenToExpression: HashMap<String, String> = HashMap()\n        private val tokenToOrderedToken: HashMap<String, String> = HashMap()\n\n        /**\n         * TokenMapper for first call ExprParser which remembers the order of expression.\n         */\n        val orderedTokenMapper: TokenMapper<String> = TokenMapper { name -> getLetter(tokenToOrderedToken, name) }\n\n        /**\n         * Returns <tt>true</tt> if this object contains no replacements.\n         *\n         * @return <tt>true</tt> if this object contains no replacements\n         */\n        fun isEmpty(): Boolean = expressionToToken.isEmpty()\n\n        /**\n         * Returns the number of replacements in this object.\n         *\n         * @return the number of replacements in this object\n         */\n        fun size(): Int = expressionToToken.size\n\n        /**\n         * Register an expression for further replacement\n         *\n         * @param expressionAstNode astNode which contains boolean expression\n         */\n        fun addExpression(expressionAstNode: ASTNode) {\n            val expressionText = expressionAstNode.textWithoutComments()\n            // support case when `boolean_expression` matches to `!boolean_expression`\n            val (expression, negativeExpression) = if (expressionText.startsWith('!')) {\n                expressionText.substring(1) to expressionText\n            } else {\n                expressionText to getNegativeExpression(expressionAstNode, expressionText)\n            }\n            val letter = getLetter(expressionToToken, expression)\n            tokenToExpression[\"!$letter\"] = negativeExpression\n            tokenToExpression[letter] = expression\n        }\n\n        /**\n         * Replaces registered expressions in provided expression\n         *\n         * @param fullExpression full boolean expression in kotlin\n         * @return full expression in jbool format\n         */\n        fun replaceExpressions(fullExpression: String): String {\n            var resultExpression = fullExpression\n            expressionToToken.keys\n                .sortedByDescending { it.length }\n                .forEach { refExpr ->\n                    resultExpression = resultExpression.replace(refExpr, expressionToToken.getValue(refExpr))\n                }\n            return resultExpression\n        }\n\n        /**\n         * Restores full expression by replacing tokens and restoring the order\n         *\n         * @param fullExpression full boolean expression in jbool format\n         * @return full boolean expression in kotlin\n         */\n        fun restoreFullExpression(fullExpression: String): String {\n            // restore order\n            var resultExpression = fullExpression\n            tokenToOrderedToken.values.forEachIndexed { index, value ->\n                resultExpression = resultExpression.replace(value, \"%${index + 1}\\$s\")\n            }\n            resultExpression = resultExpression.format(args = tokenToOrderedToken.keys.toTypedArray())\n            // restore expression\n            tokenToExpression.keys.forEachIndexed { index, value ->\n                resultExpression = resultExpression.replace(value, \"%${index + 1}\\$s\")\n            }\n            resultExpression = resultExpression.format(args = tokenToExpression.values.toTypedArray())\n            return resultExpression\n        }\n\n        private fun getLetter(letters: HashMap<String, String>, key: String) = letters\n            .computeIfAbsent(key) {\n                ('A'.code + letters.size).toChar().toString()\n            }\n\n        private fun getNegativeExpression(expressionAstNode: ASTNode, expression: String): String =\n            if (expressionAstNode.elementType == BINARY_EXPRESSION) {\n                val operation = (expressionAstNode.psi as KtBinaryExpression).operationReference.text\n                logicalInfixMethodMapping[operation]?.let {\n                    expression.replace(operation, it)\n                } ?: \"!($expression)\"\n            } else {\n                \"!$expression\"\n            }\n    }\n\n    companion object {\n        const val NAME_ID = \"boolean-expressions-rule\"\n\n        private fun <K> allRules(): RuleList<K> {\n            val rules: MutableList<Rule<*, K>> = ArrayList(RulesHelper.simplifyRules<K>().rules)\n            rules.add(DeMorgan())\n            rules.add(DistributiveLaw())\n            return RuleList(rules)\n        }\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/main/kotlin/com/saveourtool/diktat/ruleset/rules/chapter3/BracesInConditionalsAndLoopsRule.kt",
    "content": "package com.saveourtool.diktat.ruleset.rules.chapter3\n\nimport com.saveourtool.diktat.common.config.rules.RulesConfig\nimport com.saveourtool.diktat.ruleset.constants.Warnings.NO_BRACES_IN_CONDITIONALS_AND_LOOPS\nimport com.saveourtool.diktat.ruleset.rules.DiktatRule\nimport com.saveourtool.diktat.ruleset.utils.findChildrenMatching\nimport com.saveourtool.diktat.ruleset.utils.isPartOfComment\nimport com.saveourtool.diktat.ruleset.utils.isSingleLineIfElse\nimport com.saveourtool.diktat.ruleset.utils.loopType\nimport com.saveourtool.diktat.ruleset.utils.prevSibling\n\nimport org.jetbrains.kotlin.KtNodeTypes.BLOCK\nimport org.jetbrains.kotlin.KtNodeTypes.BLOCK_CODE_FRAGMENT\nimport org.jetbrains.kotlin.KtNodeTypes.BODY\nimport org.jetbrains.kotlin.KtNodeTypes.CALL_EXPRESSION\nimport org.jetbrains.kotlin.KtNodeTypes.ELSE\nimport org.jetbrains.kotlin.KtNodeTypes.IF\nimport org.jetbrains.kotlin.KtNodeTypes.LAMBDA_EXPRESSION\nimport org.jetbrains.kotlin.KtNodeTypes.REFERENCE_EXPRESSION\nimport org.jetbrains.kotlin.KtNodeTypes.SAFE_ACCESS_EXPRESSION\nimport org.jetbrains.kotlin.KtNodeTypes.THEN\nimport org.jetbrains.kotlin.KtNodeTypes.WHEN\nimport org.jetbrains.kotlin.com.intellij.lang.ASTNode\nimport org.jetbrains.kotlin.com.intellij.psi.impl.source.tree.CompositeElement\nimport org.jetbrains.kotlin.com.intellij.psi.impl.source.tree.LeafPsiElement\nimport org.jetbrains.kotlin.com.intellij.psi.impl.source.tree.PsiWhiteSpaceImpl\nimport org.jetbrains.kotlin.lexer.KtTokens.DO_KEYWORD\nimport org.jetbrains.kotlin.lexer.KtTokens.ELSE_KEYWORD\nimport org.jetbrains.kotlin.lexer.KtTokens.IF_KEYWORD\nimport org.jetbrains.kotlin.lexer.KtTokens.LBRACE\nimport org.jetbrains.kotlin.lexer.KtTokens.RBRACE\nimport org.jetbrains.kotlin.lexer.KtTokens.WHILE_KEYWORD\nimport org.jetbrains.kotlin.lexer.KtTokens.WHITE_SPACE\nimport org.jetbrains.kotlin.psi.KtBlockExpression\nimport org.jetbrains.kotlin.psi.KtElement\nimport org.jetbrains.kotlin.psi.KtIfExpression\nimport org.jetbrains.kotlin.psi.KtLoopExpression\nimport org.jetbrains.kotlin.psi.KtWhenExpression\nimport org.jetbrains.kotlin.psi.psiUtil.astReplace\nimport org.jetbrains.kotlin.psi.psiUtil.children\n\n/**\n * Rule that checks that all conditionals and loops have braces.\n */\nclass BracesInConditionalsAndLoopsRule(configRules: List<RulesConfig>) : DiktatRule(\n    NAME_ID,\n    configRules,\n    listOf(NO_BRACES_IN_CONDITIONALS_AND_LOOPS)\n) {\n    override fun logic(node: ASTNode) {\n        when (node.elementType) {\n            IF -> checkIfNode(node)\n            WHEN -> checkWhenBranches(node)\n            in loopType -> checkLoop(node)\n            else -> return\n        }\n    }\n\n    /**\n     * Check braces in if-else statements. Check for both IF and ELSE needs to be done in one method to discover single-line if-else statements correctly.\n     */\n    @Suppress(\n        \"ForbiddenComment\",\n        \"UnsafeCallOnNullableType\",\n        \"ComplexMethod\",\n        \"TOO_LONG_FUNCTION\"\n    )\n    private fun checkIfNode(node: ASTNode) {\n        val ifPsi = node.psi as KtIfExpression\n        val thenNode = ifPsi.then?.node\n        val elseKeyword = ifPsi.elseKeyword\n        val elseNode = ifPsi.`else`?.node\n        val indent = node.findIndentBeforeNode()\n\n        if (node.isSingleLineIfElse()) {\n            return\n        }\n\n        if (thenNode?.elementType != BLOCK) {\n            NO_BRACES_IN_CONDITIONALS_AND_LOOPS.warnAndFix(configRules, emitWarn, isFixMode, \"IF\",\n                (thenNode?.prevSibling { it.elementType == IF_KEYWORD } ?: node).startOffset, node) {\n                thenNode?.run {\n                    (psi as KtElement).replaceWithBlock(indent)\n                    if (elseNode != null && elseKeyword != null) {\n                        node.replaceChild(elseKeyword.prevSibling.node, PsiWhiteSpaceImpl(\" \"))\n                    }\n                }\n                    ?: run {\n                        node.insertEmptyBlockInsideThenNode(indent)\n                    }\n            }\n        }\n\n        if (elseKeyword != null && elseNode?.elementType != IF && elseNode?.elementType != BLOCK) {\n            // Looking for scope functions, for which we won't trigger\n            val callAndSafeAccessExpressionChildren = elseNode?.findChildrenMatching {\n                it.elementType == CALL_EXPRESSION || it.elementType == SAFE_ACCESS_EXPRESSION\n            }\n\n            val scopeFunctionChildren = callAndSafeAccessExpressionChildren?.flatMap {\n                it.children()\n            }?.filter {\n                it.elementType == REFERENCE_EXPRESSION\n            }\n\n            val isNodeHaveScopeFunctionChildren = scopeFunctionChildren?.any {\n                it.text in scopeFunctions\n            }\n            if (isNodeHaveScopeFunctionChildren == true) {\n                return\n            }\n\n            NO_BRACES_IN_CONDITIONALS_AND_LOOPS.warnAndFix(configRules, emitWarn, isFixMode, \"ELSE\",\n                (elseNode?.treeParent?.prevSibling { it.elementType == ELSE_KEYWORD } ?: node).startOffset, node) {\n                elseNode?.run {\n                    (psi as KtElement).replaceWithBlock(indent)\n                }\n                    ?: run {\n                        // `else` can have empty body e.g. when there is a semicolon after: `else ;`\n                        node.insertEmptyBlockInsideElseNode(indent)\n                    }\n            }\n        }\n    }\n\n    private fun ASTNode.insertEmptyBlockInsideThenNode(indent: Int) {\n        val ifPsi = psi as KtIfExpression\n        val elseKeyword = ifPsi.elseKeyword\n        val emptyThenNode = findChildByType(THEN)\n\n        emptyThenNode?.findChildByType(BLOCK_CODE_FRAGMENT) ?: run {\n            val whiteSpacesAfterCondition = ifPsi.rightParenthesis?.node?.treeNext\n\n            whiteSpacesAfterCondition?.let {\n                replaceChild(it, PsiWhiteSpaceImpl(\" \"))\n            }\n            emptyThenNode?.insertEmptyBlock(indent)\n            elseKeyword?.let {\n                addChild(PsiWhiteSpaceImpl(\" \"), elseKeyword.node)\n            }\n        }\n    }\n\n    private fun ASTNode.insertEmptyBlockInsideElseNode(indent: Int) {\n        val ifPsi = psi as KtIfExpression\n        val elseKeyword = ifPsi.elseKeyword\n        val emptyElseNode = findChildByType(ELSE)\n\n        emptyElseNode?.findChildByType(BLOCK_CODE_FRAGMENT) ?: run {\n            val whiteSpacesAfterElseKeyword = elseKeyword?.node?.treeNext\n\n            whiteSpacesAfterElseKeyword?.let {\n                replaceChild(it, PsiWhiteSpaceImpl(\" \"))\n            }\n            emptyElseNode?.insertEmptyBlock(indent)\n        }\n    }\n\n    @Suppress(\"UnsafeCallOnNullableType\")\n    private fun checkLoop(node: ASTNode) {\n        val loopBody = (node.psi as KtLoopExpression).body\n        val loopBodyNode = loopBody?.node\n\n        if (loopBodyNode == null || loopBodyNode.elementType != BLOCK) {\n            NO_BRACES_IN_CONDITIONALS_AND_LOOPS.warnAndFix(configRules, emitWarn, isFixMode,\n                node.elementType.toString(), node.startOffset, node) {\n                // fixme proper way to calculate indent? or get step size (instead of hardcoded 4)\n                val indent = node.findIndentBeforeNode()\n\n                loopBody?.run {\n                    replaceWithBlock(indent)\n                }\n                    ?: run {\n                        // this corresponds to do-while with empty body\n                        node.insertEmptyBlockInsideDoWhileNode(indent)\n                    }\n            }\n        }\n    }\n\n    private fun ASTNode.insertEmptyBlockInsideDoWhileNode(indent: Int) {\n        findChildByType(BODY) ?: run {\n            val doKeyword = findChildByType(DO_KEYWORD)\n            val whileKeyword = findChildByType(WHILE_KEYWORD)\n            val whiteSpacesAfterDoKeyword = doKeyword?.treeNext\n\n            addChild(CompositeElement(BODY), whileKeyword)\n            val emptyWhenNode = findChildByType(BODY)\n\n            whiteSpacesAfterDoKeyword?.let {\n                replaceChild(it, PsiWhiteSpaceImpl(\" \"))\n            }\n            emptyWhenNode?.insertEmptyBlock(indent)\n            addChild(PsiWhiteSpaceImpl(\" \"), whileKeyword)\n        }\n    }\n\n    private fun ASTNode.findIndentBeforeNode(): Int {\n        val isElseIfStatement = treeParent.elementType == ELSE\n        val primaryIfNode = if (isElseIfStatement) treeParent.treeParent else this\n\n        val indentNode = if (primaryIfNode.treeParent?.treeParent?.treeParent?.elementType == LAMBDA_EXPRESSION) {\n            primaryIfNode.treeParent.prevSibling { it.elementType == WHITE_SPACE }\n        } else {\n            primaryIfNode.prevSibling { it.elementType == WHITE_SPACE }\n        }\n\n        return indentNode\n            ?.text\n            ?.lines()\n            ?.last()\n            ?.count { it == ' ' } ?: 0\n    }\n\n    @Suppress(\"UnsafeCallOnNullableType\")\n    private fun checkWhenBranches(node: ASTNode) {\n        (node.psi as KtWhenExpression)\n            .entries\n            .asSequence()\n            .filter { it.expression != null && it.expression!!.node.elementType == BLOCK }\n            .map { it.expression as KtBlockExpression }\n            .filter { block ->\n                block.statements.size == 1 &&\n                        block.findChildrenMatching { it.isPartOfComment() }.isEmpty()\n            }\n            .forEach { block ->\n                NO_BRACES_IN_CONDITIONALS_AND_LOOPS.warnAndFix(configRules, emitWarn, isFixMode,\n                    \"WHEN\", block.node.startOffset, block.node) {\n                    block.astReplace(block.firstStatement!!.node.psi)\n                }\n            }\n    }\n\n    private fun KtElement.replaceWithBlock(indent: Int) {\n        this.astReplace(KtBlockExpression(\n            \"{\\n${\" \".repeat(indent + INDENT_STEP)}$text\\n${\" \".repeat(indent)}}\"\n        ))\n    }\n\n    private fun ASTNode.insertEmptyBlock(indent: Int) {\n        val emptyBlock = CompositeElement(BLOCK_CODE_FRAGMENT)\n        addChild(emptyBlock, null)\n        emptyBlock.addChild(LeafPsiElement(LBRACE, \"{\"))\n        emptyBlock.addChild(PsiWhiteSpaceImpl(\"\\n${\" \".repeat(indent)}\"))\n        emptyBlock.addChild(LeafPsiElement(RBRACE, \"}\"))\n    }\n\n    companion object {\n        private const val INDENT_STEP = 4\n        const val NAME_ID = \"races-rule\"\n        private val scopeFunctions = listOf(\"let\", \"run\", \"with\", \"apply\", \"also\")\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/main/kotlin/com/saveourtool/diktat/ruleset/rules/chapter3/ClassLikeStructuresOrderRule.kt",
    "content": "package com.saveourtool.diktat.ruleset.rules.chapter3\n\nimport com.saveourtool.diktat.common.config.rules.RulesConfig\nimport com.saveourtool.diktat.ruleset.constants.Warnings.BLANK_LINE_BETWEEN_PROPERTIES\nimport com.saveourtool.diktat.ruleset.constants.Warnings.WRONG_ORDER_IN_CLASS_LIKE_STRUCTURES\nimport com.saveourtool.diktat.ruleset.rules.DiktatRule\nimport com.saveourtool.diktat.ruleset.utils.*\nimport com.saveourtool.diktat.ruleset.utils.isPartOfComment\nimport com.saveourtool.diktat.ruleset.utils.nextSibling\nimport com.saveourtool.diktat.ruleset.utils.parent\nimport com.saveourtool.diktat.ruleset.utils.prevSibling\n\nimport org.jetbrains.kotlin.KtNodeTypes.CLASS\nimport org.jetbrains.kotlin.KtNodeTypes.CLASS_BODY\nimport org.jetbrains.kotlin.KtNodeTypes.CLASS_INITIALIZER\nimport org.jetbrains.kotlin.KtNodeTypes.ENUM_ENTRY\nimport org.jetbrains.kotlin.KtNodeTypes.FUN\nimport org.jetbrains.kotlin.KtNodeTypes.OBJECT_DECLARATION\nimport org.jetbrains.kotlin.KtNodeTypes.PROPERTY\nimport org.jetbrains.kotlin.KtNodeTypes.REFERENCE_EXPRESSION\nimport org.jetbrains.kotlin.KtNodeTypes.SECONDARY_CONSTRUCTOR\nimport org.jetbrains.kotlin.com.intellij.lang.ASTNode\nimport org.jetbrains.kotlin.com.intellij.psi.impl.source.tree.PsiWhiteSpaceImpl\nimport org.jetbrains.kotlin.com.intellij.psi.tree.IElementType\nimport org.jetbrains.kotlin.com.intellij.psi.tree.TokenSet\nimport org.jetbrains.kotlin.kdoc.lexer.KDocTokens.KDOC\nimport org.jetbrains.kotlin.lexer.KtTokens.BLOCK_COMMENT\nimport org.jetbrains.kotlin.lexer.KtTokens.COMPANION_KEYWORD\nimport org.jetbrains.kotlin.lexer.KtTokens.CONST_KEYWORD\nimport org.jetbrains.kotlin.lexer.KtTokens.EOL_COMMENT\nimport org.jetbrains.kotlin.lexer.KtTokens.IDENTIFIER\nimport org.jetbrains.kotlin.lexer.KtTokens.LATEINIT_KEYWORD\nimport org.jetbrains.kotlin.lexer.KtTokens.LBRACE\nimport org.jetbrains.kotlin.lexer.KtTokens.PRIVATE_KEYWORD\nimport org.jetbrains.kotlin.lexer.KtTokens.RBRACE\nimport org.jetbrains.kotlin.lexer.KtTokens.WHITE_SPACE\nimport org.jetbrains.kotlin.psi.KtClassBody\nimport org.jetbrains.kotlin.psi.KtProperty\nimport org.jetbrains.kotlin.psi.psiUtil.children\nimport org.jetbrains.kotlin.psi.psiUtil.parents\nimport org.jetbrains.kotlin.psi.psiUtil.siblings\n\n/**\n * Rule that checks order of declarations inside classes, interfaces and objects.\n */\nclass ClassLikeStructuresOrderRule(configRules: List<RulesConfig>) : DiktatRule(\n    NAME_ID,\n    configRules,\n    listOf(BLANK_LINE_BETWEEN_PROPERTIES, WRONG_ORDER_IN_CLASS_LIKE_STRUCTURES)\n) {\n    override fun logic(node: ASTNode) {\n        if (node.elementType == CLASS_BODY) {\n            checkDeclarationsOrderInClass(node)\n        } else if (node.elementType == PROPERTY) {\n            checkNewLinesBeforeProperty(node)\n        }\n    }\n\n    private fun checkDeclarationsOrderInClass(node: ASTNode) {\n        val allProperties = AllProperties.fromClassBody(node)\n        val initBlocks = node.getAllChildrenWithType(CLASS_INITIALIZER)\n        val constructors = node.getAllChildrenWithType(SECONDARY_CONSTRUCTOR)\n        val methods = node.getAllChildrenWithType(FUN)\n        val (usedClasses, unusedClasses) = node.getUsedAndUnusedClasses()\n        val (companionObject, objects) = node.getAllChildrenWithType(OBJECT_DECLARATION)\n            .partition { it.hasModifier(COMPANION_KEYWORD) }\n        val blocks = Blocks(\n            (node.psi as KtClassBody).enumEntries.map { it.node },\n            allProperties, objects, initBlocks, constructors,\n            methods, usedClasses, companionObject, unusedClasses\n        )\n            .allBlockFlattened()\n            .map { astNode ->\n                listOf(astNode) +\n                        astNode.siblings(false)\n                            .takeWhile { it.elementType == WHITE_SPACE || it.isPartOfComment() }\n                            .toList()\n            }\n\n        node.checkAndReorderBlocks(blocks)\n    }\n\n    @Suppress(\"UnsafeCallOnNullableType\", \"CyclomaticComplexMethod\")\n    private fun checkNewLinesBeforeProperty(node: ASTNode) {\n        // checking only top-level and class-level properties\n        if (node.treeParent.elementType != CLASS_BODY) {\n            return\n        }\n\n        val previousProperty = node.prevSibling { it.elementType == PROPERTY } ?: return\n        val nearComment = node.findChildByType(TokenSet.create(KDOC, EOL_COMMENT, BLOCK_COMMENT))\n        val prevComment = nearComment?.prevSibling()\n        val nextComment = nearComment?.nextSibling()\n        val isCorrectEolComment = (prevComment == null || !prevComment.textContains('\\n')) &&\n                nextComment == null\n\n        val hasCommentBefore = node\n            .findChildByType(TokenSet.create(KDOC, EOL_COMMENT, BLOCK_COMMENT))\n            ?.isFollowedByNewline()\n            ?: false\n        val hasAnnotationsBefore = (node.psi as KtProperty)\n            .annotationEntries\n            .any { it.node.isFollowedByNewline() }\n        val hasCustomAccessors = (node.psi as KtProperty).accessors.isNotEmpty() ||\n                (previousProperty.psi as KtProperty).accessors.isNotEmpty()\n\n        val whiteSpaceBefore = previousProperty.nextSibling { it.elementType == WHITE_SPACE } ?: return\n        val isBlankLineRequired = (!isCorrectEolComment && hasCommentBefore) || hasAnnotationsBefore || hasCustomAccessors\n        val numRequiredNewLines = 1 + (if (isBlankLineRequired) 1 else 0)\n        val actualNewLines = whiteSpaceBefore.text.count { it == '\\n' }\n        // for some cases (now - if this or previous property has custom accessors), blank line is allowed before it\n        if (!hasCustomAccessors && actualNewLines != numRequiredNewLines ||\n                hasCustomAccessors && actualNewLines > numRequiredNewLines) {\n            BLANK_LINE_BETWEEN_PROPERTIES.warnAndFix(configRules, emitWarn, isFixMode, node.getIdentifierName()?.text ?: node.text, node.startOffset, node) {\n                whiteSpaceBefore.leaveExactlyNumNewLines(numRequiredNewLines)\n            }\n        }\n    }\n\n    /**\n     * Returns nested classes grouped by whether they are used inside [this] file.\n     * [this] ASTNode should have elementType [CLASS_BODY]\n     */\n    private fun ASTNode.getUsedAndUnusedClasses() = getAllChildrenWithType(CLASS)\n        .partition { classNode ->\n            classNode.getIdentifierName()?.let { identifierNode ->\n                parents()\n                    .last()\n                    .findAllDescendantsWithSpecificType(REFERENCE_EXPRESSION)\n                    .any { ref ->\n                        ref.parent { it == classNode } == null && ref.text.contains(identifierNode.text)\n                    }\n            } ?: false\n        }\n\n    /**\n     * Checks whether all class elements in [this] node are correctly ordered and reorders them in fix mode.\n     * [this] ASTNode should have elementType [CLASS_BODY]\n     *\n     * @param blocks list of class elements with leading whitespaces and comments\n     */\n    @Suppress(\"UnsafeCallOnNullableType\")\n    private fun ASTNode.checkAndReorderBlocks(blocks: List<List<ASTNode>>) {\n        val classChildren = this.children().filter { it.elementType in childrenTypes }.toList()\n\n        check(blocks.size == classChildren.size) {\n            StringBuilder().apply {\n                append(\"`classChildren` has a size of ${classChildren.size} while `blocks` has a size of ${blocks.size}$NEWLINE\")\n\n                append(\"`blocks`:$NEWLINE\")\n                blocks.forEachIndexed { index, block ->\n                    append(\"\\t$index: ${block.firstOrNull()?.text}$NEWLINE\")\n                }\n\n                append(\"`classChildren`:$NEWLINE\")\n                classChildren.forEachIndexed { index, child ->\n                    append(\"\\t$index: ${child.text}$NEWLINE\")\n                }\n            }\n        }\n\n        if (classChildren != blocks.map { it.first() }) {\n            blocks.filterIndexed { index, pair -> classChildren[index] != pair.first() }\n                .forEach { listOfChildren ->\n                    val astNode = listOfChildren.first()\n                    WRONG_ORDER_IN_CLASS_LIKE_STRUCTURES.warnAndFix(configRules, emitWarn, isFixMode,\n                        \"${astNode.elementType}: ${astNode.findChildByType(IDENTIFIER)?.text ?: astNode.text}\", astNode.startOffset, astNode) {\n                        removeRange(findChildByType(LBRACE)!!.treeNext, findChildByType(RBRACE)!!)\n                        blocks.reversed()\n                            .forEach { bodyChild ->\n                                bodyChild.forEach { this.addChild(it, this.children().take(2).last()) }\n                            }\n                        // Add newline before the closing `}`. All other newlines will be properly formatted by `NewlinesRule`.\n                        this.addChild(PsiWhiteSpaceImpl(\"\\n\"), this.lastChildNode)\n                    }\n                }\n        }\n    }\n\n    /**\n     * Data class containing different groups of properties in file\n     *\n     * @property loggers loggers (for example, properties called `log` or `logger`)\n     * @property constProperties `const val`s\n     * @property properties all other properties\n     * @property lateInitProperties `lateinit var`s\n     */\n    private data class AllProperties(\n        val loggers: List<ASTNode>,\n        val constProperties: List<ASTNode>,\n        val properties: List<ASTNode>,\n        val lateInitProperties: List<ASTNode>\n    ) {\n        companion object {\n            /**\n             * Create [AllProperties] wrapper from node with type [CLASS_BODY]\n             *\n             * @param node an ASTNode with type [CLASS_BODY]\n             * @return an instance of [AllProperties]\n             */\n            @Suppress(\"UnsafeCallOnNullableType\")\n            fun fromClassBody(node: ASTNode): AllProperties {\n                val allProperties = node.getAllChildrenWithType(PROPERTY)\n                val constProperties = allProperties.filterByModifier(CONST_KEYWORD)\n                val lateInitProperties = allProperties.filterByModifier(LATEINIT_KEYWORD)\n                val referencesFromSameScope = allProperties.mapNotNull { it.getIdentifierName()?.text }\n                val loggers = allProperties.filterByModifier(PRIVATE_KEYWORD)\n                    .filterNot { astNode ->\n                        /*\n                         * A `const` field named \"logger\" is unlikely to be a logger.\n                         */\n                        astNode in constProperties\n                    }\n                    .filterNot { astNode ->\n                        /*\n                         * A `lateinit` field named \"logger\" is unlikely to be a logger.\n                         */\n                        astNode in lateInitProperties\n                    }\n                    .filter { astNode ->\n                        astNode.getIdentifierName()?.text?.matches(loggerPropertyRegex) ?: false\n                    }\n                    .let {\n                        getLoggerDependencyNames(it)\n                    }\n                    .filter { (_, dependencyReferences) ->\n                        dependencyReferences.all {\n                            it !in referencesFromSameScope\n                        }\n                    }\n                    .keys\n                    .toList()\n\n                val properties = allProperties.filter { it !in lateInitProperties && it !in loggers && it !in constProperties }\n                return AllProperties(loggers, constProperties, properties, lateInitProperties)\n            }\n\n            @Suppress(\"TYPE_ALIAS\")\n            private fun getLoggerDependencyNames(loggers: List<ASTNode>): Map<ASTNode, List<String>> = loggers.map { astNode ->\n                astNode to astNode.findAllDescendantsWithSpecificType(REFERENCE_EXPRESSION, false)\n            }.associate { (astNode, possibleDependencies) ->\n                astNode to possibleDependencies.map { it.text }\n            }\n        }\n    }\n\n    /**\n     * @property enumEntries if this class is a enum class, list of its entries. Otherwise an empty list.\n     * @property allProperties an instance of [AllProperties]\n     * @property objects objects\n     * @property initBlocks `init` blocks\n     * @property constructors constructors\n     * @property methods functions\n     * @property usedClasses nested classes that are used in the enclosing class\n     * @property companion `companion object`s\n     * @property unusedClasses nested classes that are *not* used in the enclosing class\n     */\n    private data class Blocks(val enumEntries: List<ASTNode>,\n                              val allProperties: AllProperties,\n                              val objects: List<ASTNode>,\n                              val initBlocks: List<ASTNode>,\n                              val constructors: List<ASTNode>,\n                              val methods: List<ASTNode>,\n                              val usedClasses: List<ASTNode>,\n                              val companion: List<ASTNode>,\n                              val unusedClasses: List<ASTNode>\n    ) {\n        init {\n            require(companion.size in 0..1) { \"There is more than one companion object in class\" }\n        }\n\n        /**\n         * @return all groups of structures in the class\n         */\n        fun allBlocks() = with(allProperties) {\n            listOf(enumEntries, loggers, constProperties, properties, lateInitProperties, objects,\n                initBlocks, constructors, methods, usedClasses, companion, unusedClasses)\n        }\n\n        /**\n         * @return all blocks as a flattened list of [ASTNode]s\n         */\n        fun allBlockFlattened() = allBlocks().flatten()\n    }\n\n    companion object {\n        const val NAME_ID = \"class-like-structures\"\n        private val childrenTypes = listOf(PROPERTY, CLASS, CLASS_INITIALIZER, SECONDARY_CONSTRUCTOR, FUN, OBJECT_DECLARATION, ENUM_ENTRY)\n    }\n}\n\nprivate fun Iterable<ASTNode>.filterByModifier(modifier: IElementType) = filter {\n    it.findLeafWithSpecificType(modifier) != null\n}\n"
  },
  {
    "path": "diktat-rules/src/main/kotlin/com/saveourtool/diktat/ruleset/rules/chapter3/CollapseIfStatementsRule.kt",
    "content": "package com.saveourtool.diktat.ruleset.rules.chapter3\n\nimport com.saveourtool.diktat.common.config.rules.RuleConfiguration\nimport com.saveourtool.diktat.common.config.rules.RulesConfig\nimport com.saveourtool.diktat.common.config.rules.getRuleConfig\nimport com.saveourtool.diktat.ruleset.constants.Warnings\nimport com.saveourtool.diktat.ruleset.rules.DiktatRule\nimport com.saveourtool.diktat.ruleset.utils.KotlinParser\n\nimport org.jetbrains.kotlin.KtNodeTypes.BINARY_EXPRESSION\nimport org.jetbrains.kotlin.KtNodeTypes.IF\nimport org.jetbrains.kotlin.KtNodeTypes.OPERATION_REFERENCE\nimport org.jetbrains.kotlin.KtNodeTypes.THEN\nimport org.jetbrains.kotlin.com.intellij.lang.ASTNode\nimport org.jetbrains.kotlin.lexer.KtTokens.BLOCK_COMMENT\nimport org.jetbrains.kotlin.lexer.KtTokens.EOL_COMMENT\nimport org.jetbrains.kotlin.lexer.KtTokens.LBRACE\nimport org.jetbrains.kotlin.lexer.KtTokens.LPAR\nimport org.jetbrains.kotlin.lexer.KtTokens.RBRACE\nimport org.jetbrains.kotlin.lexer.KtTokens.RPAR\nimport org.jetbrains.kotlin.lexer.KtTokens.WHITE_SPACE\nimport org.jetbrains.kotlin.psi.KtBlockExpression\nimport org.jetbrains.kotlin.psi.KtIfExpression\nimport org.jetbrains.kotlin.psi.psiUtil.children\n\nimport java.util.Stack\n\ntypealias PlaceOfWarningForCurrentNode = Pair<Int, ASTNode>\n\n/**\n * Rule for redundant nested if-statements, which could be collapsed into a single one\n */\nclass CollapseIfStatementsRule(configRules: List<RulesConfig>) : DiktatRule(\n    NAME_ID,\n    configRules,\n    listOf(\n        Warnings.COLLAPSE_IF_STATEMENTS\n    )\n) {\n    private val configuration by lazy {\n        CollapseIfStatementsConfiguration(\n            configRules.getRuleConfig(Warnings.COLLAPSE_IF_STATEMENTS)?.configuration ?: emptyMap()\n        )\n    }\n\n    // We hold the warnings, which we raised, since in case of multi nested if-statement,\n    // there are could be several identical warning for one line\n    private val listOfWarnings: MutableSet<PlaceOfWarningForCurrentNode> = mutableSetOf()\n\n    override fun logic(node: ASTNode) {\n        if (node.elementType == IF) {\n            process(node)\n        }\n    }\n\n    private fun process(node: ASTNode) {\n        val startCollapseFromLevel = configuration.startCollapseFromNestedLevel\n        val listOfNestedNodes: Stack<ASTNode> = Stack()\n\n        var nestedIfNode = findNestedIf(node)\n        while (nestedIfNode != null) {\n            listOfNestedNodes.push(nestedIfNode)\n            nestedIfNode = findNestedIf(nestedIfNode)\n        }\n        val nestedLevel = listOfNestedNodes.size + 1\n        if (nestedLevel < startCollapseFromLevel) {\n            return\n        }\n        while (listOfNestedNodes.isNotEmpty()) {\n            val currNode = listOfNestedNodes.pop()\n            // Since the external `if` statement is not the direct parent,\n            // we need multiple steps to take the required one\n            // BLOCK -> THEN -> IF\n            val currParentNode = currNode.treeParent.treeParent.treeParent\n            if (listOfWarnings.add(currNode.startOffset to currNode)) {\n                Warnings.COLLAPSE_IF_STATEMENTS.warnAndFix(\n                    configRules, emitWarn, isFixMode,\n                    \"avoid using redundant nested if-statements\", currNode.startOffset, currNode\n                ) {\n                    collapse(currParentNode, currNode)\n                }\n            }\n        }\n    }\n\n    private fun findNestedIf(parentNode: ASTNode): ASTNode? {\n        val parentThenNode = (parentNode.psi as KtIfExpression).then?.node ?: return null\n        val nestedIfNode = parentThenNode.findChildByType(IF) ?: return null\n        // We won't collapse if-statements, if some of them have `else` node\n        if ((parentNode.psi as KtIfExpression).`else` != null ||\n                (nestedIfNode.psi as KtIfExpression).`else` != null) {\n            return null\n        }\n        // We monitor which types of nodes are followed before and after nested `if`\n        // and we allow only a limited number of types to pass through.\n        // Otherwise discovered `if` is not nested\n        // We don't expect KDOC in `if-statements`, since it's a bad practise, and such code by meaning of our\n        // code analyzer is invalid\n        // However, if in some case we will hit the KDOC, than we won't collapse statements\n        val listOfNodesBeforeNestedIf = parentThenNode.getChildren(null).takeWhile { it.elementType != IF }\n        val listOfNodesAfterNestedIf = parentThenNode.getChildren(null).takeLastWhile { it != parentThenNode.findChildByType(IF) }\n        val allowedTypes = listOf(LBRACE, WHITE_SPACE, RBRACE, BLOCK_COMMENT, EOL_COMMENT)\n        if (listOfNodesBeforeNestedIf.any { it.elementType !in allowedTypes } ||\n                listOfNodesAfterNestedIf.any { it.elementType !in allowedTypes }) {\n            return null\n        }\n        return nestedIfNode\n    }\n\n    private fun takeCommentsBeforeNestedIf(node: ASTNode): List<ASTNode> {\n        val thenNode = (node.psi as KtIfExpression).then?.node\n        return thenNode?.children()\n            ?.takeWhile { it.elementType != IF }\n            ?.filter {\n                it.elementType == EOL_COMMENT || it.elementType == BLOCK_COMMENT\n            }\n            ?.toList() ?: emptyList()\n    }\n\n    private fun collapse(parentNode: ASTNode, nestedNode: ASTNode) {\n        collapseConditions(parentNode, nestedNode)\n        collapseThenBlocks(parentNode, nestedNode)\n    }\n\n    private fun collapseConditions(parentNode: ASTNode, nestedNode: ASTNode) {\n        // If there are comments before nested if, we will move them into parent condition\n        val comments = takeCommentsBeforeNestedIf(parentNode)\n        val commentsText = if (comments.isNotEmpty()) {\n            comments.joinToString(prefix = \"\\n\", postfix = \"\\n\", separator = \"\\n\") { it.text }\n        } else {\n            \" \"\n        }\n        // Merge parent and nested conditions\n        val parentConditionText = extractConditions(parentNode)\n        val nestedCondition = (nestedNode.psi as KtIfExpression).condition\n        val nestedConditionText = extractConditions(nestedNode)\n        // If the nested condition is compound,\n        // we need to put it to the brackets, according algebra of logic\n        val mergeCondition =\n            if (nestedCondition?.node?.elementType == BINARY_EXPRESSION &&\n                    nestedCondition?.node?.findChildByType(OPERATION_REFERENCE)?.text == \"||\"\n            ) {\n                \"if ($parentConditionText &&$commentsText($nestedConditionText)) {}\"\n            } else {\n                \"if ($parentConditionText &&$commentsText$nestedConditionText) {}\"\n            }\n        val newParentIfNode = KotlinParser().createNode(mergeCondition)\n        // Remove THEN block\n        newParentIfNode.removeChild(newParentIfNode.lastChildNode)\n        // Remove old `if` from parent\n        parentNode.removeRange(parentNode.firstChildNode, parentNode.findChildByType(THEN))\n        // Add to parent all child from new `if` node\n        var addAfter = parentNode.firstChildNode\n        newParentIfNode.getChildren(null).forEachIndexed { index, child ->\n            parentNode.addChild(child, addAfter)\n            addAfter = parentNode.children().drop(index + 1).first()\n        }\n    }\n\n    // If condition contains comments, we need additional actions\n    // Because of `node.condition` will ignore comments\n    private fun extractConditions(node: ASTNode): String {\n        val condition = node.getChildren(null)\n            .takeLastWhile { it != node.findChildByType(LPAR) }\n            .takeWhile { it != node.findChildByType(RPAR) }\n        return condition.joinToString(\"\") { it.text }\n    }\n\n    private fun collapseThenBlocks(parentNode: ASTNode, nestedNode: ASTNode) {\n        // Remove comments from parent node, since we already moved them into parent condition\n        val comments = takeCommentsBeforeNestedIf(parentNode)\n        comments.forEach {\n            if (it.treeNext.elementType == WHITE_SPACE &&\n                    it.treePrev.elementType == WHITE_SPACE) {\n                parentNode.removeChild(it.treePrev)\n            }\n            parentNode.removeChild(it)\n        }\n        // Merge parent and nested `THEN` blocks\n        val nestedThenNode = (nestedNode.psi as KtIfExpression).then\n        val nestedContent = (nestedThenNode as KtBlockExpression).children().toMutableList()\n        // Remove {, }, and white spaces\n        repeat(2) {\n            val firstElType = nestedContent.first().elementType\n            if (firstElType == WHITE_SPACE ||\n                    firstElType == LBRACE) {\n                nestedContent.removeFirst()\n            }\n            val lastElType = nestedContent.last().elementType\n            if (lastElType == WHITE_SPACE ||\n                    lastElType == RBRACE) {\n                nestedContent.removeLast()\n            }\n        }\n        val nestedThenText = nestedContent.joinToString(\"\") { it.text }\n        val newNestedNode = KotlinParser().createNode(nestedThenText).treeParent\n        val parentThenNode = (parentNode.psi as KtIfExpression).then?.node\n        newNestedNode.getChildren(null).forEach {\n            parentThenNode?.addChild(it, nestedNode)\n        }\n        parentThenNode?.removeChild(nestedNode)\n    }\n\n    /**\n     * [RuleConfiguration] for configuration\n     */\n    class CollapseIfStatementsConfiguration(config: Map<String, String>) : RuleConfiguration(config) {\n        /**\n         *  Collapse statements only if nested level more than this value\n         */\n        val startCollapseFromNestedLevel = config[\"startCollapseFromNestedLevel\"]?.toInt() ?: DEFAULT_NESTED_LEVEL\n    }\n\n    companion object {\n        private const val DEFAULT_NESTED_LEVEL = 2\n        const val NAME_ID = \"collapse-if\"\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/main/kotlin/com/saveourtool/diktat/ruleset/rules/chapter3/ConsecutiveSpacesRule.kt",
    "content": "package com.saveourtool.diktat.ruleset.rules.chapter3\n\nimport com.saveourtool.diktat.common.config.rules.RuleConfiguration\nimport com.saveourtool.diktat.common.config.rules.RulesConfig\nimport com.saveourtool.diktat.common.config.rules.getRuleConfig\nimport com.saveourtool.diktat.ruleset.constants.Warnings.TOO_MANY_CONSECUTIVE_SPACES\nimport com.saveourtool.diktat.ruleset.rules.DiktatRule\nimport com.saveourtool.diktat.ruleset.utils.isWhiteSpaceWithNewline\nimport com.saveourtool.diktat.ruleset.utils.parent\n\nimport org.jetbrains.kotlin.KtNodeTypes.ENUM_ENTRY\nimport org.jetbrains.kotlin.com.intellij.lang.ASTNode\nimport org.jetbrains.kotlin.com.intellij.psi.impl.source.tree.LeafElement\nimport org.jetbrains.kotlin.lexer.KtTokens.EOL_COMMENT\nimport org.jetbrains.kotlin.lexer.KtTokens.WHITE_SPACE\n\n/**\n * This visitor covers recommendation 3.8 of Huawei code style. It covers following recommendations:\n * 1) No spaces should be inserted for horizontal alignment\n * 2) If saveInitialFormattingForEnums is true then white spaces in enums will not be affected\n *\n */\nclass ConsecutiveSpacesRule(configRules: List<RulesConfig>) : DiktatRule(\n    NAME_ID,\n    configRules,\n    listOf(TOO_MANY_CONSECUTIVE_SPACES),\n) {\n    override fun logic(node: ASTNode) {\n        val configuration = TooManySpacesRuleConfiguration(\n            configRules.getRuleConfig(TOO_MANY_CONSECUTIVE_SPACES)?.configuration ?: emptyMap())\n\n        if (node.elementType == WHITE_SPACE) {\n            checkWhiteSpace(node, configuration)\n        }\n    }\n\n    private fun checkWhiteSpace(node: ASTNode, configuration: TooManySpacesRuleConfiguration) {\n        if (configuration.enumInitialFormatting) {\n            checkWhiteSpaceEnum(node, configuration)\n        } else {\n            squeezeSpacesToOne(node, configuration)\n        }\n    }\n\n    private fun checkWhiteSpaceEnum(node: ASTNode, configuration: TooManySpacesRuleConfiguration) {\n        val isInEnum = isWhitespaceInEnum(node)\n\n        if (!isInEnum) {\n            squeezeSpacesToOne(node, configuration)\n        }\n    }\n\n    private fun isWhitespaceInEnum(node: ASTNode): Boolean = node.parent(ENUM_ENTRY) != null\n\n    private fun squeezeSpacesToOne(node: ASTNode, configuration: TooManySpacesRuleConfiguration) {\n        val spaces = node.textLength\n        if (spaces > configuration.numberOfSpaces && !node.isWhiteSpaceWithNewline() &&\n                !node.hasEolComment()) {\n            TOO_MANY_CONSECUTIVE_SPACES.warnAndFix(configRules, emitWarn, isFixMode,\n                \"found: $spaces. need to be: ${configuration.numberOfSpaces}\", node.startOffset, node) {\n                node.squeezeSpaces()\n            }\n        }\n    }\n\n    private fun ASTNode.hasEolComment(): Boolean = this.treeNext.elementType == EOL_COMMENT\n\n    private fun ASTNode.squeezeSpaces() = (this as LeafElement).rawReplaceWithText(\" \")\n\n    /**\n     * [RuleConfiguration] for consecutive spaces\n     */\n    class TooManySpacesRuleConfiguration(config: Map<String, String>) : RuleConfiguration(config) {\n        /**\n         * Maximum allowed number of consecutive spaces (not counting indentation)\n         */\n        val numberOfSpaces = config[\"maxSpaces\"]?.toIntOrNull() ?: MAX_SPACES\n\n        /**\n         * Whether formatting for enums should be kept without checking\n         */\n        val enumInitialFormatting = config[\"saveInitialFormattingForEnums\"]?.toBoolean() ?: false\n    }\n\n    companion object {\n        private const val MAX_SPACES = 1\n        const val NAME_ID = \"too-many-spaces\"\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/main/kotlin/com/saveourtool/diktat/ruleset/rules/chapter3/DebugPrintRule.kt",
    "content": "package com.saveourtool.diktat.ruleset.rules.chapter3\n\nimport com.saveourtool.diktat.common.config.rules.RulesConfig\nimport com.saveourtool.diktat.ruleset.constants.Warnings\nimport com.saveourtool.diktat.ruleset.rules.DiktatRule\n\nimport org.jetbrains.kotlin.KtNodeTypes\nimport org.jetbrains.kotlin.com.intellij.lang.ASTNode\nimport org.jetbrains.kotlin.com.intellij.psi.tree.TokenSet\nimport org.jetbrains.kotlin.lexer.KtTokens\n\n/**\n * This rule detects `print()` or `println()`.\n * Assumption that it's a debug logging\n *\n */\nclass DebugPrintRule(configRules: List<RulesConfig>) : DiktatRule(\n    NAME_ID,\n    configRules,\n    listOf(Warnings.DEBUG_PRINT)\n) {\n    override fun logic(node: ASTNode) {\n        checkPrintln(node)\n        checkJsConsole(node)\n    }\n\n    // check kotlin.io.print()/kotlin.io.println()\n    private fun checkPrintln(node: ASTNode) {\n        if (node.elementType == KtNodeTypes.CALL_EXPRESSION) {\n            val referenceExpression = node.findChildByType(KtNodeTypes.REFERENCE_EXPRESSION)?.text\n            val valueArgumentList = node.findChildByType(KtNodeTypes.VALUE_ARGUMENT_LIST)\n            if (referenceExpression in setOf(\"print\", \"println\") &&\n                    node.treePrev?.elementType != KtTokens.DOT &&\n                    valueArgumentList?.getChildren(TokenSet.create(KtNodeTypes.VALUE_ARGUMENT))?.size?.let { it <= 1 } == true &&\n                    node.findChildByType(KtNodeTypes.LAMBDA_ARGUMENT) == null) {\n                Warnings.DEBUG_PRINT.warn(\n                    configRules, emitWarn,\n                    \"found $referenceExpression()\", node.startOffset, node,\n                )\n            }\n        }\n    }\n\n    // check kotlin.js.console.*()\n    private fun checkJsConsole(node: ASTNode) {\n        if (node.elementType == KtNodeTypes.DOT_QUALIFIED_EXPRESSION) {\n            val isConsole = node.firstChildNode.let { referenceExpression ->\n                referenceExpression.elementType == KtNodeTypes.REFERENCE_EXPRESSION &&\n                        referenceExpression.firstChildNode.let { it.elementType == KtTokens.IDENTIFIER && it.text == \"console\" }\n            }\n            if (isConsole) {\n                val logMethod = node.lastChildNode\n                    .takeIf { it.elementType == KtNodeTypes.CALL_EXPRESSION }\n                    ?.takeIf { it.findChildByType(KtNodeTypes.LAMBDA_ARGUMENT) == null }\n                    ?.firstChildNode\n                    ?.takeIf { it.elementType == KtNodeTypes.REFERENCE_EXPRESSION }\n                    ?.text\n                if (logMethod in setOf(\"error\", \"info\", \"log\", \"warn\")) {\n                    Warnings.DEBUG_PRINT.warn(\n                        configRules, emitWarn,\n                        \"found console.$logMethod()\", node.startOffset, node,\n                    )\n                }\n            }\n        }\n    }\n\n    internal companion object {\n        const val NAME_ID = \"debug-print\"\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/main/kotlin/com/saveourtool/diktat/ruleset/rules/chapter3/EmptyBlock.kt",
    "content": "package com.saveourtool.diktat.ruleset.rules.chapter3\n\nimport com.saveourtool.diktat.common.config.rules.RuleConfiguration\nimport com.saveourtool.diktat.common.config.rules.RulesConfig\nimport com.saveourtool.diktat.common.config.rules.getRuleConfig\nimport com.saveourtool.diktat.ruleset.constants.Warnings.EMPTY_BLOCK_STRUCTURE_ERROR\nimport com.saveourtool.diktat.ruleset.rules.DiktatRule\nimport com.saveourtool.diktat.ruleset.utils.*\n\nimport org.jetbrains.kotlin.KtNodeTypes\nimport org.jetbrains.kotlin.KtNodeTypes.CALL_EXPRESSION\nimport org.jetbrains.kotlin.KtNodeTypes.DOT_QUALIFIED_EXPRESSION\nimport org.jetbrains.kotlin.KtNodeTypes.FUNCTION_LITERAL\nimport org.jetbrains.kotlin.KtNodeTypes.LAMBDA_EXPRESSION\nimport org.jetbrains.kotlin.KtNodeTypes.VALUE_ARGUMENT_LIST\nimport org.jetbrains.kotlin.KtNodeTypes.VALUE_PARAMETER\nimport org.jetbrains.kotlin.com.intellij.lang.ASTNode\nimport org.jetbrains.kotlin.com.intellij.psi.impl.source.tree.LeafPsiElement\nimport org.jetbrains.kotlin.com.intellij.psi.impl.source.tree.PsiWhiteSpaceImpl\nimport org.jetbrains.kotlin.lexer.KtTokens.IDENTIFIER\nimport org.jetbrains.kotlin.lexer.KtTokens.RBRACE\nimport org.jetbrains.kotlin.lexer.KtTokens.WHITE_SPACE\nimport org.jetbrains.kotlin.psi.psiUtil.parents\n\n/**\n * Rule that checks if empty code blocks (`{  }`) are used and checks their formatting.\n */\nclass EmptyBlock(configRules: List<RulesConfig>) : DiktatRule(\n    NAME_ID,\n    configRules,\n    listOf(EMPTY_BLOCK_STRUCTURE_ERROR)\n) {\n    override fun logic(node: ASTNode) {\n        val configuration = EmptyBlockStyleConfiguration(\n            configRules.getRuleConfig(EMPTY_BLOCK_STRUCTURE_ERROR)?.configuration ?: emptyMap()\n        )\n        searchNode(node, configuration)\n    }\n\n    private fun searchNode(node: ASTNode, configuration: EmptyBlockStyleConfiguration) {\n        val newNode = node.findLBrace()?.treeParent ?: return\n        if (!isAllowedEmptyBlock(newNode) && newNode.isBlockEmpty()) {\n            checkEmptyBlock(newNode, configuration)\n        }\n    }\n\n    private fun isNewLine(node: ASTNode) =\n        node.findChildByType(WHITE_SPACE)?.text?.contains(\"\\n\") ?: false\n\n    private fun isAllowedEmptyBlock(node: ASTNode) = node.treeParent.isOverridden() ||\n            isAnonymousSamClass(node) ||\n            isLambdaUsedAsFunction(node) ||\n            isKotlinLogging(node)\n\n    @Suppress(\"UnsafeCallOnNullableType\", \"TOO_LONG_FUNCTION\")\n    private fun checkEmptyBlock(node: ASTNode, configuration: EmptyBlockStyleConfiguration) {\n        if (!configuration.emptyBlockExist) {\n            EMPTY_BLOCK_STRUCTURE_ERROR.warn(configRules, emitWarn, \"empty blocks are forbidden unless it is function with override keyword\",\n                node.startOffset, node)\n        } else {\n            node.findParentNodeWithSpecificType(KtNodeTypes.LAMBDA_ARGUMENT)?.let {\n                // Lambda body is always has a BLOCK -> run { } - (LBRACE, WHITE_SPACE, BLOCK \"\", RBRACE)\n                if (isNewLine(node)) {\n                    val freeText = \"do not put newlines in empty lambda\"\n                    EMPTY_BLOCK_STRUCTURE_ERROR.warnAndFix(configRules, emitWarn, isFixMode, freeText, node.startOffset, node) {\n                        val whiteSpaceNode = node.findChildByType(WHITE_SPACE)\n                        whiteSpaceNode?.let {\n                            node.replaceChild(whiteSpaceNode, PsiWhiteSpaceImpl(\" \"))\n                        }\n                    }\n                }\n                return\n            }\n            val space = node.findChildByType(RBRACE)!!.treePrev\n            if (configuration.emptyBlockNewline && !space.text.contains(\"\\n\")) {\n                EMPTY_BLOCK_STRUCTURE_ERROR.warnAndFix(configRules, emitWarn, isFixMode, \"different style for empty block\",\n                    node.startOffset, node) {\n                    if (space.elementType == WHITE_SPACE) {\n                        (space.treeNext as LeafPsiElement).rawReplaceWithText(\"\\n\")\n                    } else {\n                        node.addChild(PsiWhiteSpaceImpl(\"\\n\"), space.treeNext)\n                    }\n                }\n            } else if (!configuration.emptyBlockNewline && space.text.contains(\"\\n\")) {\n                EMPTY_BLOCK_STRUCTURE_ERROR.warnAndFix(configRules, emitWarn, isFixMode, \"different style for empty block\",\n                    node.startOffset, node) {\n                    node.removeChild(space)\n                }\n            }\n        }\n    }\n\n    @Suppress(\"UnsafeCallOnNullableType\")\n    private fun isAnonymousSamClass(node: ASTNode): Boolean =\n        if (node.elementType == FUNCTION_LITERAL && node.hasParent(CALL_EXPRESSION)) {\n            // We are checking identifier because it is not class in AST,\n            // SAM conversions are indistinguishable from lambdas.\n            // So we just verify that identifier is in PascalCase\n            val valueArgument = node.findParentNodeWithSpecificType(CALL_EXPRESSION)!!\n            valueArgument.findLeafWithSpecificType(IDENTIFIER)?.text?.isPascalCase() ?: false\n        } else {\n            false\n        }\n\n    @Suppress(\"UnsafeCallOnNullableType\")\n    private fun isLambdaUsedAsFunction(node: ASTNode): Boolean {\n        val parents = node.parents()\n        return when {\n            parents.any { it.elementType == CALL_EXPRESSION } -> {\n                val callExpression = parents.find { it.elementType == CALL_EXPRESSION }!!\n                // excepting cases like list.map { }. In this case call expression will not have value argument list\n                // And in this case: Parser.parse({}, some, thing) it will have value argument list\n                callExpression.hasChildOfType(VALUE_ARGUMENT_LIST)\n            }\n            parents.any { it.elementType == LAMBDA_EXPRESSION } -> {\n                val lambdaExpression = parents.find { it.elementType == LAMBDA_EXPRESSION }!!\n                // cases like A({}). Here Lambda expression is used as a value parameter.\n                lambdaExpression.treeParent.elementType == VALUE_PARAMETER\n            }\n            else -> false\n        }\n    }\n\n    private fun isKotlinLogging(node: ASTNode): Boolean = node.findParentNodeWithSpecificType(DOT_QUALIFIED_EXPRESSION)\n        ?.text\n        ?.replace(\" \", \"\")\n        .let {\n            it == \"KotlinLogging.logger{}\"\n        }\n\n    /**\n     * [RuleConfiguration] for empty blocks formatting\n     */\n    class EmptyBlockStyleConfiguration(config: Map<String, String>) : RuleConfiguration(config) {\n        /**\n         * Whether empty code blocks should be allowed\n         */\n        val emptyBlockExist = config[\"allowEmptyBlocks\"]?.toBoolean() ?: false\n\n        /**\n         * Whether a newline after `{` is required in an empty block\n         */\n        val emptyBlockNewline = config[\"styleEmptyBlockWithNewline\"]?.toBoolean() ?: true\n    }\n\n    companion object {\n        const val NAME_ID = \"empty-block-structure\"\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/main/kotlin/com/saveourtool/diktat/ruleset/rules/chapter3/EnumsSeparated.kt",
    "content": "package com.saveourtool.diktat.ruleset.rules.chapter3\n\nimport com.saveourtool.diktat.common.config.rules.RulesConfig\nimport com.saveourtool.diktat.ruleset.constants.Warnings.ENUMS_SEPARATED\nimport com.saveourtool.diktat.ruleset.rules.DiktatRule\nimport com.saveourtool.diktat.ruleset.utils.AstNodePredicate\nimport com.saveourtool.diktat.ruleset.utils.allSiblings\nimport com.saveourtool.diktat.ruleset.utils.appendNewline\nimport com.saveourtool.diktat.ruleset.utils.appendNewlineMergingWhiteSpace\nimport com.saveourtool.diktat.ruleset.utils.getAllChildrenWithType\nimport com.saveourtool.diktat.ruleset.utils.hasChildOfType\nimport com.saveourtool.diktat.ruleset.utils.isClassEnum\nimport com.saveourtool.diktat.ruleset.utils.isWhiteSpaceWithNewline\n\nimport org.jetbrains.kotlin.KtNodeTypes.CLASS\nimport org.jetbrains.kotlin.KtNodeTypes.CLASS_BODY\nimport org.jetbrains.kotlin.KtNodeTypes.ENUM_ENTRY\nimport org.jetbrains.kotlin.com.intellij.lang.ASTNode\nimport org.jetbrains.kotlin.com.intellij.psi.impl.source.tree.LeafPsiElement\nimport org.jetbrains.kotlin.com.intellij.psi.impl.source.tree.PsiWhiteSpaceImpl\nimport org.jetbrains.kotlin.lexer.KtTokens.BLOCK_COMMENT\nimport org.jetbrains.kotlin.lexer.KtTokens.COMMA\nimport org.jetbrains.kotlin.lexer.KtTokens.EOL_COMMENT\nimport org.jetbrains.kotlin.lexer.KtTokens.IDENTIFIER\nimport org.jetbrains.kotlin.lexer.KtTokens.LBRACE\nimport org.jetbrains.kotlin.lexer.KtTokens.RBRACE\nimport org.jetbrains.kotlin.lexer.KtTokens.SEMICOLON\nimport org.jetbrains.kotlin.lexer.KtTokens.WHITE_SPACE\n\n/**\n * Rule that checks enum classes formatting\n */\nclass EnumsSeparated(configRules: List<RulesConfig>) : DiktatRule(\n    NAME_ID,\n    configRules,\n    listOf(ENUMS_SEPARATED),\n) {\n    override fun logic(node: ASTNode) {\n        if (node.elementType == CLASS && node.hasChildOfType(CLASS_BODY) && node.isClassEnum()) {\n            checkEnumEntry(node)\n        }\n    }\n\n    // Fixme prefer enum classes if it is possible instead of variables\n    @Suppress(\"UnsafeCallOnNullableType\")\n    private fun checkEnumEntry(node: ASTNode) {\n        val enumEntries = node.findChildByType(CLASS_BODY)!!.getAllChildrenWithType(ENUM_ENTRY)\n        if (enumEntries.isEmpty() || (isEnumSimple(enumEntries) && isEnumOneLine(enumEntries))) {\n            return\n        }\n        enumEntries.forEach { enumEntry ->\n            if (!enumEntry.treeNext.isWhiteSpaceWithNewline()) {\n                ENUMS_SEPARATED.warnAndFix(configRules, emitWarn, isFixMode, \"enum entries must end with a line break\",\n                    enumEntry.startOffset, enumEntry) {\n                    enumEntry.appendNewline()\n                }\n            }\n        }\n        checkLastEnum(enumEntries.last())\n    }\n\n    private fun isEnumOneLine(nodes: List<ASTNode>) =\n        nodes.dropLast(1).none { it.treeNext.isWhiteSpaceWithNewline() }\n\n    private fun isEnumSimple(enumEntries: List<ASTNode>): Boolean {\n        enumEntries.forEach { node ->\n            if (!simpleValue.containsAll(node.getChildren(null).map { it.elementType })) {\n                return false\n            }\n        }\n        return simpleEnum.containsAll(enumEntries\n            .last()\n            .allSiblings(withSelf = true)\n            .map { it.elementType })\n    }\n\n    @Suppress(\"UnsafeCallOnNullableType\")\n    private fun checkLastEnum(node: ASTNode) {\n        if (!node.hasChildOfType(SEMICOLON)) {\n            ENUMS_SEPARATED.warnAndFix(configRules, emitWarn, isFixMode, \"enums must end with semicolon\",\n                node.startOffset, node) {\n                node.addChild(LeafPsiElement(SEMICOLON, \";\"), null)\n                node.addChild(PsiWhiteSpaceImpl(\"\\n\"), node.findChildByType(SEMICOLON)!!)\n            }\n        } else if (!node.findChildByType(SEMICOLON)!!.treePrev.isWhiteSpaceWithNewline()) {\n            ENUMS_SEPARATED.warnAndFix(configRules, emitWarn, isFixMode, \"semicolon must be on a new line\",\n                node.startOffset, node) {\n                node.appendNewlineMergingWhiteSpace(node.findChildByType(SEMICOLON)!!, node.findChildByType(SEMICOLON)!!)\n            }\n        }\n        if (!node.hasChildOfType(COMMA)) {\n            ENUMS_SEPARATED.warnAndFix(configRules, emitWarn, isFixMode, \"last enum entry must end with a comma\",\n                node.startOffset, node) {\n                val commaLocation = node.findChildByType(SEMICOLON)!!.findLatestTreePrevMatching {\n                    it.elementType !in setOf(EOL_COMMENT, BLOCK_COMMENT, WHITE_SPACE)\n                }\n                node.addChild(LeafPsiElement(COMMA, \",\"), commaLocation.treeNext)\n            }\n        }\n    }\n\n    private fun ASTNode.findLatestTreePrevMatching(predicate: AstNodePredicate): ASTNode {\n        val result = this.treePrev\n        return if (predicate(result)) result else result.findLatestTreePrevMatching(predicate)\n    }\n\n    companion object {\n        const val NAME_ID = \"enum-separated\"\n        private val simpleValue = listOf(IDENTIFIER, WHITE_SPACE, COMMA, SEMICOLON)\n        private val simpleEnum = listOf(ENUM_ENTRY, WHITE_SPACE, LBRACE, RBRACE)\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/main/kotlin/com/saveourtool/diktat/ruleset/rules/chapter3/LineLength.kt",
    "content": "package com.saveourtool.diktat.ruleset.rules.chapter3\n\nimport com.saveourtool.diktat.common.config.rules.RuleConfiguration\nimport com.saveourtool.diktat.common.config.rules.RulesConfig\nimport com.saveourtool.diktat.common.config.rules.getRuleConfig\nimport com.saveourtool.diktat.ruleset.constants.Warnings.LONG_LINE\nimport com.saveourtool.diktat.ruleset.rules.DiktatRule\nimport com.saveourtool.diktat.ruleset.utils.KotlinParser\nimport com.saveourtool.diktat.ruleset.utils.appendNewlineMergingWhiteSpace\nimport com.saveourtool.diktat.ruleset.utils.calculateLineColByOffset\nimport com.saveourtool.diktat.ruleset.utils.countCodeLines\nimport com.saveourtool.diktat.ruleset.utils.findAllNodesWithConditionOnLine\nimport com.saveourtool.diktat.ruleset.utils.findChildAfter\nimport com.saveourtool.diktat.ruleset.utils.findChildBefore\nimport com.saveourtool.diktat.ruleset.utils.findChildrenMatching\nimport com.saveourtool.diktat.ruleset.utils.findParentNodeWithSpecificType\nimport com.saveourtool.diktat.ruleset.utils.getAllChildrenWithType\nimport com.saveourtool.diktat.ruleset.utils.getFirstChildWithType\nimport com.saveourtool.diktat.ruleset.utils.getLineNumber\nimport com.saveourtool.diktat.ruleset.utils.hasChildOfType\nimport com.saveourtool.diktat.ruleset.utils.isChildAfterAnother\nimport com.saveourtool.diktat.ruleset.utils.isWhiteSpace\nimport com.saveourtool.diktat.ruleset.utils.isWhiteSpaceWithNewline\nimport com.saveourtool.diktat.ruleset.utils.nextSibling\nimport com.saveourtool.diktat.ruleset.utils.prevSibling\n\nimport io.github.oshai.kotlinlogging.KotlinLogging\nimport org.jetbrains.kotlin.KtNodeTypes.BINARY_EXPRESSION\nimport org.jetbrains.kotlin.KtNodeTypes.BLOCK\nimport org.jetbrains.kotlin.KtNodeTypes.DOT_QUALIFIED_EXPRESSION\nimport org.jetbrains.kotlin.KtNodeTypes.FUN\nimport org.jetbrains.kotlin.KtNodeTypes.FUNCTION_LITERAL\nimport org.jetbrains.kotlin.KtNodeTypes.IMPORT_LIST\nimport org.jetbrains.kotlin.KtNodeTypes.OPERATION_REFERENCE\nimport org.jetbrains.kotlin.KtNodeTypes.PACKAGE_DIRECTIVE\nimport org.jetbrains.kotlin.KtNodeTypes.PARENTHESIZED\nimport org.jetbrains.kotlin.KtNodeTypes.POSTFIX_EXPRESSION\nimport org.jetbrains.kotlin.KtNodeTypes.PREFIX_EXPRESSION\nimport org.jetbrains.kotlin.KtNodeTypes.PROPERTY\nimport org.jetbrains.kotlin.KtNodeTypes.SAFE_ACCESS_EXPRESSION\nimport org.jetbrains.kotlin.KtNodeTypes.STRING_TEMPLATE\nimport org.jetbrains.kotlin.KtNodeTypes.VALUE_ARGUMENT_LIST\nimport org.jetbrains.kotlin.KtNodeTypes.WHEN_CONDITION_EXPRESSION\nimport org.jetbrains.kotlin.KtNodeTypes.WHEN_ENTRY\nimport org.jetbrains.kotlin.com.intellij.lang.ASTNode\nimport org.jetbrains.kotlin.com.intellij.psi.impl.source.tree.LeafPsiElement\nimport org.jetbrains.kotlin.com.intellij.psi.impl.source.tree.PsiWhiteSpaceImpl\nimport org.jetbrains.kotlin.com.intellij.psi.tree.IElementType\nimport org.jetbrains.kotlin.kdoc.lexer.KDocTokens.MARKDOWN_INLINE_LINK\nimport org.jetbrains.kotlin.kdoc.lexer.KDocTokens.TEXT\nimport org.jetbrains.kotlin.lexer.KtTokens.ANDAND\nimport org.jetbrains.kotlin.lexer.KtTokens.ARROW\nimport org.jetbrains.kotlin.lexer.KtTokens.COMMA\nimport org.jetbrains.kotlin.lexer.KtTokens.DOT\nimport org.jetbrains.kotlin.lexer.KtTokens.ELVIS\nimport org.jetbrains.kotlin.lexer.KtTokens.EOL_COMMENT\nimport org.jetbrains.kotlin.lexer.KtTokens.EQ\nimport org.jetbrains.kotlin.lexer.KtTokens.EQEQ\nimport org.jetbrains.kotlin.lexer.KtTokens.EQEQEQ\nimport org.jetbrains.kotlin.lexer.KtTokens.EXCL\nimport org.jetbrains.kotlin.lexer.KtTokens.EXCLEQ\nimport org.jetbrains.kotlin.lexer.KtTokens.EXCLEQEQEQ\nimport org.jetbrains.kotlin.lexer.KtTokens.GT\nimport org.jetbrains.kotlin.lexer.KtTokens.GTEQ\nimport org.jetbrains.kotlin.lexer.KtTokens.LBRACE\nimport org.jetbrains.kotlin.lexer.KtTokens.LPAR\nimport org.jetbrains.kotlin.lexer.KtTokens.LT\nimport org.jetbrains.kotlin.lexer.KtTokens.LTEQ\nimport org.jetbrains.kotlin.lexer.KtTokens.OROR\nimport org.jetbrains.kotlin.lexer.KtTokens.RBRACE\nimport org.jetbrains.kotlin.lexer.KtTokens.RPAR\nimport org.jetbrains.kotlin.lexer.KtTokens.SAFE_ACCESS\nimport org.jetbrains.kotlin.lexer.KtTokens.WHITE_SPACE\nimport org.jetbrains.kotlin.psi.stubs.elements.KtFileElementType\n\nimport java.net.MalformedURLException\nimport java.net.URL\n\n/**\n * The rule checks for lines in the file that exceed the maximum length.\n * Rule ignores URL in KDoc. This rule can also fix some particular corner cases.\n * This inspection can fix long binary expressions in condition inside `if`,\n * in property declarations and in single line functions.\n */\n@Suppress(\"ForbiddenComment\")\nclass LineLength(configRules: List<RulesConfig>) : DiktatRule(\n    NAME_ID,\n    configRules,\n    listOf(LONG_LINE)\n) {\n    private val configuration by lazy {\n        LineLengthConfiguration(\n            configRules.getRuleConfig(LONG_LINE)?.configuration ?: emptyMap()\n        )\n    }\n    private lateinit var positionByOffset: (Int) -> Pair<Int, Int>\n\n    override fun logic(node: ASTNode) {\n        var currentFixNumber = 0\n        var isFixedSmthInPreviousStep: Boolean\n\n        // loop that trying to fix LineLength rule warnings until warnings run out\n        do {\n            isFixedSmthInPreviousStep = false\n            currentFixNumber++\n\n            if (node.elementType == KtFileElementType.INSTANCE) {\n                node.getChildren(null).forEach {\n                    if (it.elementType != PACKAGE_DIRECTIVE && it.elementType != IMPORT_LIST) {\n                        val isFixedSmthInChildNode = checkLength(it, configuration)\n\n                        if (!isFixedSmthInPreviousStep && isFixedSmthInChildNode) {\n                            isFixedSmthInPreviousStep = true\n                        }\n                    }\n                }\n            }\n        } while (isFixedSmthInPreviousStep && currentFixNumber < MAX_FIX_NUMBER)\n\n        if (currentFixNumber == MAX_FIX_NUMBER) {\n            log.error {\n                \"The limit on the number of consecutive fixes has been reached. There may be a bug causing an endless loop of fixes.\"\n            }\n        }\n    }\n\n    @Suppress(\n        \"UnsafeCallOnNullableType\",\n        \"TOO_LONG_FUNCTION\",\n        \"FUNCTION_BOOLEAN_PREFIX\"\n    )\n    private fun checkLength(node: ASTNode, configuration: LineLengthConfiguration): Boolean {\n        var isFixedSmthInChildNode = false\n\n        var offset = 0\n        node.text.lines().forEach { line ->\n            if (line.length > configuration.lineLength) {\n                val newNode = node.psi.findElementAt(offset + configuration.lineLength.toInt() - 1)!!.node\n\n                if ((newNode.elementType != TEXT && newNode.elementType != MARKDOWN_INLINE_LINK) || !isKdocValid(newNode)) {\n                    positionByOffset = node.treeParent.calculateLineColByOffset()\n\n                    val fixableType = isFixable(newNode, configuration)\n\n                    LONG_LINE.warnOnlyOrWarnAndFix(\n                        configRules, emitWarn,\n                        \"max line length ${configuration.lineLength}, but was ${line.length}\",\n                        offset + node.startOffset, node,\n                        shouldBeAutoCorrected = fixableType !is None,\n                        isFixMode,\n                    ) {\n                        val textBeforeFix = node.text\n                        val textLenBeforeFix = node.textLength\n                        val blankLinesBeforeFix = node.text.lines().size - countCodeLines(node)\n\n                        fixableType.fix()\n\n                        val textAfterFix = node.text\n                        val textLenAfterFix = node.textLength\n                        val blankLinesAfterFix = node.text.lines().size - countCodeLines(node)\n\n                        // checking that any fix may have been made\n                        isFixedSmthInChildNode = fixableType !is None\n\n                        // for cases when text doesn't change, and then we need to stop fixes\n                        if (textBeforeFix == textAfterFix) {\n                            isFixedSmthInChildNode = false\n                        }\n\n                        // in some kernel cases of long lines, when in fix step we adding `\\n` to certain place of the line\n                        // and part of the line is transferred to the new line, this part may still be too long,\n                        // and then in next fix step we can start generating unnecessary blank lines,\n                        // to detect this we count blank lines and make unfix, if necessary\n                        if (blankLinesAfterFix > blankLinesBeforeFix) {\n                            isFixedSmthInChildNode = false\n                            fixableType.unFix()\n                        } else {\n                            // we should keep in mind, that in the course of fixing we change the offset\n                            // offset for all next nodes changed to this delta\n                            offset += (textLenAfterFix - textLenBeforeFix)\n                        }\n                    }\n                }\n            }\n\n            offset += line.length + 1\n        }\n\n        return isFixedSmthInChildNode\n    }\n\n    @Suppress(\n        \"TOO_LONG_FUNCTION\",\n        \"LongMethod\",\n        \"ComplexMethod\",\n        \"GENERIC_VARIABLE_WRONG_DECLARATION\",\n    )\n    private fun isFixable(wrongNode: ASTNode, configuration: LineLengthConfiguration): LongLineFixableCases {\n        var parent = wrongNode\n        var stringOrDot: ASTNode? = null\n        do {\n            when (parent.elementType) {\n                BINARY_EXPRESSION, PARENTHESIZED -> {\n                    val parentIsValArgListOrFunLitOrWhenEntry = listOf(VALUE_ARGUMENT_LIST, FUNCTION_LITERAL, WHEN_CONDITION_EXPRESSION)\n                    findParentNodeMatching(parent, parentIsValArgListOrFunLitOrWhenEntry)?.let {\n                        parent = it\n                    } ?: run {\n                        val splitOffset = searchRightSplitAfterOperationReference(parent, configuration)?.second\n                        splitOffset?.let {\n                            val parentIsBiExprOrParenthesized = parent.treeParent.elementType in listOf(BINARY_EXPRESSION, PARENTHESIZED)\n                            val parentIsFunOrProperty = parent.treeParent.elementType in listOf(FUN, PROPERTY)\n                            if (parentIsBiExprOrParenthesized || (parentIsFunOrProperty && splitOffset > configuration.lineLength)) {\n                                parent = parent.treeParent\n                            } else {\n                                return checkBinaryExpression(parent, configuration)\n                            }\n                        }\n                            ?: run {\n                                stringOrDot?.let {\n                                    val returnElem = checkStringTemplateAndDotQualifiedExpression(it, configuration)\n                                    if (returnElem !is None) {\n                                        return returnElem\n                                    }\n                                }\n                                parent = parent.treeParent\n                            }\n                    }\n                }\n                FUN, PROPERTY -> return checkFunAndProperty(parent)\n                VALUE_ARGUMENT_LIST -> parent.findParentNodeWithSpecificType(BINARY_EXPRESSION)?.let {\n                    parent = it\n                } ?: return checkArgumentsList(parent, configuration)\n                WHEN_ENTRY -> return WhenEntry(parent)\n                WHEN_CONDITION_EXPRESSION -> return None()\n                EOL_COMMENT -> return checkComment(parent, configuration)\n                FUNCTION_LITERAL -> return Lambda(parent)\n                STRING_TEMPLATE, DOT_QUALIFIED_EXPRESSION, SAFE_ACCESS_EXPRESSION -> {\n                    stringOrDot = parent\n                    val parentIsBinExpOrValArgListOrWhenEntry = listOf(BINARY_EXPRESSION, VALUE_ARGUMENT_LIST, WHEN_CONDITION_EXPRESSION)\n                    findParentNodeMatching(parent, parentIsBinExpOrValArgListOrWhenEntry)?.let {\n                        parent = it\n                    } ?: run {\n                        val returnElem = checkStringTemplateAndDotQualifiedExpression(parent, configuration)\n                        if (returnElem !is None) {\n                            return returnElem\n                        }\n                        parent = parent.treeParent\n                    }\n                }\n                else -> parent = parent.treeParent\n            }\n        } while (parent.treeParent != null)\n        return None()\n    }\n\n    private fun findParentNodeMatching(node: ASTNode, listType: List<IElementType>): ASTNode? {\n        listType.forEach { type ->\n            node.findParentNodeWithSpecificType(type)?.let {\n                return it\n            }\n        }\n        return null\n    }\n\n    @Suppress(\"PARAMETER_NAME_IN_OUTER_LAMBDA\")\n    private fun checkArgumentsList(node: ASTNode, configuration: LineLengthConfiguration): LongLineFixableCases {\n        node.findParentNodeWithSpecificType(WHEN_ENTRY)?.let {\n            it.findChildByType(BLOCK)?.run {\n                return ValueArgumentList(node, configuration, positionByOffset)\n            } ?: return WhenEntry(it)\n        }\n        return ValueArgumentList(node, configuration, positionByOffset)\n    }\n\n    /**\n     * Parses the existing binary expression and passes the necessary parameters to the fix function for splitting\n     */\n    private fun checkBinaryExpression(node: ASTNode, configuration: LineLengthConfiguration): LongLineFixableCases {\n        val leftOffset = positionByOffset(node.firstChildNode.startOffset).second\n        val binList: MutableList<ASTNode> = mutableListOf()\n        searchBinaryExpression(node, binList)\n        if (binList.size == 1) {\n            return BinaryExpression(node)\n        }\n        return LongBinaryExpression(node, configuration, leftOffset, binList, positionByOffset)\n    }\n\n    @Suppress(\"TOO_MANY_LINES_IN_LAMBDA\", \"GENERIC_VARIABLE_WRONG_DECLARATION\")\n    private fun checkStringTemplateAndDotQualifiedExpression(\n        node: ASTNode,\n        configuration: LineLengthConfiguration\n    ): LongLineFixableCases {\n        val isPropertyOrFun = listOf(PROPERTY, FUN)\n        val funOrPropertyNode = findParentNodeMatching(node, isPropertyOrFun)\n        funOrPropertyNode?.let {\n            if (it.hasChildOfType(EQ)) {\n                val positionByOffset = positionByOffset(it.getFirstChildWithType(EQ)?.startOffset ?: 0).second\n                if (positionByOffset < configuration.lineLength / 2) {\n                    val returnedClass = parserStringAndDot(node, configuration)\n                    if (returnedClass !is None) {\n                        return returnedClass\n                    }\n                }\n                return FunAndProperty(it)\n            }\n            return parserStringAndDot(node, configuration)\n        } ?: return parserStringAndDot(node, configuration)\n    }\n\n    private fun parserStringAndDot(node: ASTNode, configuration: LineLengthConfiguration) =\n        if (node.elementType == STRING_TEMPLATE) {\n            parserStringTemplate(node, configuration)\n        } else {\n            parserDotQualifiedExpression(node, configuration)\n        }\n\n    /**\n     * This class finds where the string can be split\n     *\n     * @return StringTemplate - if the string can be split,\n     *         BinaryExpression - if there is two concatenated strings and new line should be inserted after `+`\n     *         None - if the string can't be split\n     */\n    @Suppress(\"TOO_LONG_FUNCTION\", \"UnsafeCallOnNullableType\")\n    private fun parserStringTemplate(node: ASTNode, configuration: LineLengthConfiguration): LongLineFixableCases {\n        var multiLineOffset = 0\n        val leftOffset = if (node.text.lines().size > 1) {\n            node\n                .text\n                .lines()\n                .takeWhile { it.length < configuration.lineLength }\n                .forEach { multiLineOffset += it.length }\n            node\n                .text\n                .lines()\n                .first { it.length > configuration.lineLength }\n                .takeWhile { it.isWhitespace() }\n                .count()\n        } else {\n            positionByOffset(node.startOffset).second\n        }\n        val delimiterIndex =\n            node.text.substring(0, multiLineOffset + configuration.lineLength.toInt() - leftOffset).lastIndexOf(' ')\n        if (delimiterIndex == -1) {\n            // we can't split this string, however may be we can move it entirely:\n            // case when new line should be inserted after `+`. Example: \"first\" + \"second\"\n            node.treeParent.findChildByType(OPERATION_REFERENCE)?.let {\n                return BinaryExpression(node.treeParent)\n            }\n            // can't fix this case\n            return None()\n        }\n        // check, that space to split is a part of text - not code\n        // If the space split is part of the code, then there is a chance of breaking the code when fixing, that why we should ignore it\n        val isSpaceIsWhiteSpace = node.psi\n            .findElementAt(delimiterIndex)!!\n            .node\n            .isWhiteSpace()\n        if (isSpaceIsWhiteSpace) {\n            return None()\n        }\n        // minus 2 here as we are inserting ` +` and we don't want it to exceed line length\n        val shouldAddTwoSpaces =\n            (multiLineOffset == 0) && (leftOffset + delimiterIndex > configuration.lineLength.toInt() - 2)\n        val correcterDelimiter = if (shouldAddTwoSpaces) {\n            node.text.substring(0, delimiterIndex - 2).lastIndexOf(' ')\n        } else {\n            delimiterIndex\n        }\n        if (correcterDelimiter == -1) {\n            return None()\n        }\n        return StringTemplate(node, correcterDelimiter, multiLineOffset == 0)\n    }\n\n    private fun parserDotQualifiedExpression(\n        wrongNode: ASTNode,\n        configuration: LineLengthConfiguration\n    ): LongLineFixableCases {\n        val nodeDot = searchRightSplitBeforeDotOrSafeAccess(wrongNode, configuration, DOT)\n        val nodeSafeAccess = searchRightSplitBeforeDotOrSafeAccess(wrongNode, configuration, SAFE_ACCESS)\n        return nodeDot?.let {\n            DotQualifiedExpression(wrongNode)\n        } ?: nodeSafeAccess?.let {\n            DotQualifiedExpression(wrongNode)\n        } ?: None()\n    }\n\n    private fun checkFunAndProperty(wrongNode: ASTNode) =\n        if (wrongNode.hasChildOfType(EQ)) FunAndProperty(wrongNode) else None()\n\n    private fun checkComment(wrongNode: ASTNode, configuration: LineLengthConfiguration): LongLineFixableCases {\n        val leftOffset = positionByOffset(wrongNode.startOffset).second\n        val stringBeforeCommentContent = wrongNode.text.takeWhile { it == ' ' || it == '/' }\n        if (stringBeforeCommentContent.length >= configuration.lineLength.toInt() - leftOffset) {\n            return None()\n        }\n        val indexLastSpace = wrongNode.text.substring(stringBeforeCommentContent.length, configuration.lineLength.toInt() - leftOffset).lastIndexOf(' ')\n        val isNewLine = wrongNode.treePrev?.isWhiteSpaceWithNewline() ?: wrongNode.treeParent?.treePrev?.isWhiteSpaceWithNewline() ?: false\n        if (isNewLine && indexLastSpace == -1) {\n            return None()\n        }\n        return Comment(wrongNode, isNewLine, indexLastSpace + stringBeforeCommentContent.length)\n    }\n\n    // fixme json method\n    private fun isKdocValid(node: ASTNode) = try {\n        if (node.elementType == TEXT) {\n            URL(node.text.split(\"\\\\s\".toRegex()).last { it.isNotEmpty() })\n        } else {\n            URL(node.text.substring(node.text.indexOfFirst { it == ']' } + 2, node.textLength - 1))\n        }\n        true\n    } catch (e: MalformedURLException) {\n        false\n    }\n\n    /**\n     * This method uses recursion to store binary node in the order in which they are located\n     * Also binList contains nodes with PREFIX_EXPRESSION element type ( !isFoo(), !isValid)\n     *\n     *@param node node in which to search\n     *@param binList mutable list of ASTNode to store nodes\n     */\n    private fun searchBinaryExpression(node: ASTNode, binList: MutableList<ASTNode>) {\n        if (node.hasChildOfType(BINARY_EXPRESSION) || node.hasChildOfType(PARENTHESIZED) || node.hasChildOfType(POSTFIX_EXPRESSION)) {\n            node.getChildren(null)\n                .forEach {\n                    searchBinaryExpression(it, binList)\n                }\n        }\n        if (node.elementType == BINARY_EXPRESSION) {\n            binList.add(node)\n            binList.add(node.treeParent.findChildByType(PREFIX_EXPRESSION) ?: return)\n        }\n    }\n\n    /**\n     * This method uses recursion to store dot qualified expression node in the order in which they are located\n     * Also dotList contains nodes with PREFIX_EXPRESSION element type ( !isFoo(), !isValid))\n     *\n     *@param node node in which to search\n     *@param dotList mutable list of ASTNode to store nodes\n     */\n    private fun searchDotOrSafeAccess(node: ASTNode, dotList: MutableList<ASTNode>) {\n        if (node.elementType == DOT_QUALIFIED_EXPRESSION || node.elementType == SAFE_ACCESS_EXPRESSION || node.elementType == POSTFIX_EXPRESSION) {\n            node.getChildren(null)\n                .forEach {\n                    searchDotOrSafeAccess(it, dotList)\n                }\n            if (node.elementType != POSTFIX_EXPRESSION) {\n                dotList.add(node)\n            }\n        }\n    }\n\n    /**\n     * Finds the first binary expression closer to the separator\n     */\n    @Suppress(\"UnsafeCallOnNullableType\")\n    private fun searchRightSplitAfterOperationReference(\n        parent: ASTNode,\n        configuration: LineLengthConfiguration,\n    ): Pair<ASTNode, Int>? {\n        val list: MutableList<ASTNode> = mutableListOf()\n        searchBinaryExpression(parent, list)\n        return list.asSequence()\n            .map {\n                it to positionByOffset(it.getFirstChildWithType(OPERATION_REFERENCE)!!.startOffset).second\n            }\n            .sortedBy { it.second }\n            .lastOrNull { (it, offset) ->\n                offset + (it.getFirstChildWithType(OPERATION_REFERENCE)?.text?.length ?: 0) <= configuration.lineLength + 1\n            }\n    }\n\n    /**\n     * Finds the first dot or safe access closer to the separator\n     */\n    @Suppress(\n        \"MAGIC_NUMBER\",\n        \"MagicNumber\",\n        \"PARAMETER_NAME_IN_OUTER_LAMBDA\"\n    )\n    private fun searchRightSplitBeforeDotOrSafeAccess(\n        parent: ASTNode,\n        configuration: LineLengthConfiguration,\n        type: IElementType\n    ): Pair<ASTNode, Int>? {\n        val list: MutableList<ASTNode> = mutableListOf()\n        searchDotOrSafeAccess(parent, list)\n        val offsetFromMaximum = 10\n        return list.asSequence()\n            .map {\n                val offset = it.getFirstChildWithType(type)?.run {\n                    positionByOffset(this.startOffset).second\n                } ?: run {\n                    configuration.lineLength.toInt() + offsetFromMaximum\n                }\n                it to offset\n            }\n            .sortedBy { it.second }\n            .lastOrNull { (_, offset) ->\n                offset <= configuration.lineLength + 1\n            }\n    }\n\n    /**\n     *\n     * [RuleConfiguration] for maximum line length\n     */\n    class LineLengthConfiguration(config: Map<String, String>) : RuleConfiguration(config) {\n        /**\n         * Maximum allowed line length\n         */\n        val lineLength = config[\"lineLength\"]?.toLongOrNull() ?: MAX_LENGTH\n    }\n\n    /**\n     * Class LongLineFixableCases is parent class for several specific error classes\n     */\n    @Suppress(\"KDOC_NO_CONSTRUCTOR_PROPERTY\", \"MISSING_KDOC_CLASS_ELEMENTS\")  // todo add proper docs\n    abstract class LongLineFixableCases(val node: ASTNode) {\n        /**\n         * Abstract fix - fix anything nodes\n         */\n        abstract fun fix()\n\n        /**\n         * Function unFix - unfix incorrect unnecessary fix-changes\n         */\n        @Suppress(\"EmptyFunctionBlock\")\n        open fun unFix() {\n            // Nothing to do here by default.\n        }\n    }\n\n    /**\n     * Class None show error that long line have unidentified type or something else that we can't analyze\n     */\n    private class None : LongLineFixableCases(KotlinParser().createNode(\"ERROR\")) {\n        @Suppress(\"EmptyFunctionBlock\")\n        override fun fix() {}\n    }\n\n    /**\n     * Class Comment show that long line should be split in comment\n     * @property hasNewLineBefore flag to handle type of comment: ordinary comment (long part of which should be moved to the next line)\n     * and inline comments (which should be moved entirely to the previous line)\n     * @property indexLastSpace index of last space to substring comment\n     */\n    private class Comment(\n        node: ASTNode,\n        val hasNewLineBefore: Boolean,\n        val indexLastSpace: Int = 0\n    ) : LongLineFixableCases(node) {\n        override fun fix() {\n            if (this.hasNewLineBefore) {\n                val indexLastSpace = this.indexLastSpace\n                val nodeText = \"//${node.text.substring(indexLastSpace, node.text.length)}\"\n                node.treeParent.apply {\n                    addChild(LeafPsiElement(EOL_COMMENT, node.text.substring(0, indexLastSpace)), node)\n                    addChild(PsiWhiteSpaceImpl(\"\\n\"), node)\n                    addChild(LeafPsiElement(EOL_COMMENT, nodeText), node)\n                    removeChild(node)\n                }\n            } else {\n                if (node.treePrev.isWhiteSpace()) {\n                    node.treeParent.removeChild(node.treePrev)\n                }\n\n                // for cases when property has multiline initialization, and then we need to move comment before first line\n                val newLineNodeOnPreviousLine = if (node.treeParent.elementType == PROPERTY) {\n                    node.treeParent.treeParent.findChildrenMatching {\n                        it.elementType == WHITE_SPACE && node.treeParent.treeParent.isChildAfterAnother(node.treeParent, it) && it.textContains('\\n')\n                    }\n                        .lastOrNull()\n                } else {\n                    node.findAllNodesWithConditionOnLine(node.getLineNumber() - 1) {\n                        it.elementType == WHITE_SPACE && it.textContains('\\n')\n                    }?.lastOrNull()\n                }\n\n                newLineNodeOnPreviousLine?.let {\n                    val parent = node.treeParent\n                    parent.removeChild(node)\n                    newLineNodeOnPreviousLine.treeParent.addChild(node, newLineNodeOnPreviousLine.treeNext)\n                    newLineNodeOnPreviousLine.treeParent.addChild(PsiWhiteSpaceImpl(\"\\n\"), newLineNodeOnPreviousLine.treeNext.treeNext)\n                }\n            }\n        }\n    }\n\n    /**\n     * Class StringTemplate show that long line should be split in string template\n     * @property delimiterIndex\n     * @property isOneLineString\n     */\n    private class StringTemplate(\n        node: ASTNode,\n        val delimiterIndex: Int,\n        val isOneLineString: Boolean\n    ) : LongLineFixableCases(node) {\n        override fun fix() {\n            val incorrectText = node.text\n            val firstPart = incorrectText.substring(0, delimiterIndex)\n            val secondPart = incorrectText.substring(delimiterIndex, incorrectText.length)\n            val textBetweenParts =\n                if (isOneLineString) {\n                    \"\\\" +\\n\\\"\"\n                } else {\n                    \"\\n\"\n                }\n            val correctNode = KotlinParser().createNode(\"$firstPart$textBetweenParts$secondPart\")\n            node.treeParent.replaceChild(node, correctNode)\n        }\n    }\n\n    /**\n     * Class BinaryExpression show that long line should be split in short binary expression? after operation reference\n     */\n    private class BinaryExpression(node: ASTNode) : LongLineFixableCases(node) {\n        override fun fix() {\n            val binNode = if (node.elementType == PARENTHESIZED) {\n                node.findChildByType(BINARY_EXPRESSION)\n            } else {\n                node\n            }\n            val nodeOperationReference = binNode?.findChildByType(OPERATION_REFERENCE)\n            val nextNode = if (nodeOperationReference?.firstChildNode?.elementType != ELVIS) {\n                nodeOperationReference?.treeNext\n            } else {\n                if (nodeOperationReference?.treePrev?.elementType == WHITE_SPACE) {\n                    nodeOperationReference?.treePrev\n                } else {\n                    nodeOperationReference\n                }\n            }\n            binNode?.appendNewlineMergingWhiteSpace(nextNode, nextNode)\n        }\n    }\n\n    /**\n     * Class LongBinaryExpression show that long line should be split between other parts long binary expression,\n     * after one of operation reference\n     * @property maximumLineLength is number of maximum line length\n     * @property leftOffset is offset before start [node]\n     * @property binList is list of Binary Expression which are children of [node]\n     * @property positionByOffset\n     */\n    private class LongBinaryExpression(\n        node: ASTNode,\n        val maximumLineLength: LineLengthConfiguration,\n        val leftOffset: Int,\n        val binList: MutableList<ASTNode>,\n        var positionByOffset: (Int) -> Pair<Int, Int>\n    ) : LongLineFixableCases(node) {\n        /**\n         * Fix a binary expression -\n         * - If the transfer is done on the Elvis operator, then transfers it to a new line\n         * - If not on the Elvis operator, then transfers it to a new line after the operation reference\n         */\n        @Suppress(\"UnsafeCallOnNullableType\")\n        override fun fix() {\n            val anySplitNode = searchSomeSplitInBinaryExpression(node, maximumLineLength)\n            val rightSplitNode = anySplitNode[0] ?: anySplitNode[1] ?: anySplitNode[2]\n            val nodeOperationReference = rightSplitNode?.first?.getFirstChildWithType(OPERATION_REFERENCE)\n            rightSplitNode?.let {\n                val nextNode = if (nodeOperationReference?.firstChildNode?.elementType != ELVIS) {\n                    nodeOperationReference?.treeNext\n                } else {\n                    if (nodeOperationReference?.treePrev?.elementType == WHITE_SPACE) {\n                        nodeOperationReference?.treePrev\n                    } else {\n                        nodeOperationReference\n                    }\n                }\n                if (!nextNode?.text?.contains((\"\\n\"))!!) {\n                    rightSplitNode.first.appendNewlineMergingWhiteSpace(nextNode, nextNode)\n                }\n            }\n        }\n\n        /**\n         * This method stored all the nodes that have [BINARY_EXPRESSION] or [PREFIX_EXPRESSION] element type.\n         * - First elem in List - Logic Binary Expression (`&&`, `||`)\n         * - Second elem in List - Comparison Binary Expression (`>`, `<`, `==`, `>=`, `<=`, `!=`, `===`, `!==`)\n         * - Other types (Arithmetical and Bitwise operation) (`+`, `-`, `*`, `/`, `%`, `>>`, `<<`, `&`, `|`, `~`, `^`, `>>>`, `<<<`,\n         *   `*=`, `+=`, `-=`, `/=`, `%=`, `++`, `--`, `in` `!in`, etc.)\n         *\n         * @return the list of node-to-offset pairs.\n         */\n        @Suppress(\"TYPE_ALIAS\")\n        private fun searchSomeSplitInBinaryExpression(parent: ASTNode, configuration: LineLengthConfiguration): List<Pair<ASTNode, Int>?> {\n            val logicListOperationReference = listOf(OROR, ANDAND)\n            val compressionListOperationReference = listOf(GT, LT, EQEQ, GTEQ, LTEQ, EXCLEQ, EQEQEQ, EXCLEQEQEQ)\n            val binList: MutableList<ASTNode> = mutableListOf()\n            searchBinaryExpression(parent, binList)\n            val rightBinList = binList.map {\n                it to positionByOffset(it.getFirstChildWithType(OPERATION_REFERENCE)?.startOffset ?: 0).second\n            }\n                .sortedBy { it.second }\n                .reversed()\n            val returnList: MutableList<Pair<ASTNode, Int>?> = mutableListOf()\n            addInSmartListBinExpression(returnList, rightBinList, logicListOperationReference, configuration)\n            addInSmartListBinExpression(returnList, rightBinList, compressionListOperationReference, configuration)\n            val expression = rightBinList.firstOrNull { (it, offset) ->\n                val binOperationReference = it.getFirstChildWithType(OPERATION_REFERENCE)?.firstChildNode?.elementType\n                offset + (it.getFirstChildWithType(OPERATION_REFERENCE)?.text?.length ?: 0) <= configuration.lineLength + 1 &&\n                        binOperationReference !in logicListOperationReference && binOperationReference !in compressionListOperationReference && binOperationReference != EXCL\n            }\n            returnList.add(expression)\n            return returnList\n        }\n\n        private fun searchBinaryExpression(node: ASTNode, binList: MutableList<ASTNode>) {\n            if (node.hasChildOfType(BINARY_EXPRESSION) || node.hasChildOfType(PARENTHESIZED) || node.hasChildOfType(POSTFIX_EXPRESSION)) {\n                node.getChildren(null)\n                    .forEach {\n                        searchBinaryExpression(it, binList)\n                    }\n            }\n            if (node.elementType == BINARY_EXPRESSION) {\n                binList.add(node)\n                binList.add(node.treeParent.findChildByType(PREFIX_EXPRESSION) ?: return)\n            }\n        }\n\n        /**\n         * Runs through the sorted list [rightBinList], finds its last element, the type of which is included in the set [typesList] and adds it in the list [returnList]\n         */\n        @Suppress(\"TYPE_ALIAS\")\n        private fun addInSmartListBinExpression(\n            returnList: MutableList<Pair<ASTNode, Int>?>,\n            rightBinList: List<Pair<ASTNode, Int>>,\n            typesList: List<IElementType>,\n            configuration: LineLengthConfiguration\n        ) {\n            val expression = rightBinList.firstOrNull { (it, offset) ->\n                val binOperationReference = it.getFirstChildWithType(OPERATION_REFERENCE)\n                offset + (it.getFirstChildWithType(OPERATION_REFERENCE)?.text?.length ?: 0) <= configuration.lineLength + 1 &&\n                        binOperationReference?.firstChildNode?.elementType in typesList\n            }\n            returnList.add(expression)\n        }\n    }\n\n    /**\n     * Class FunAndProperty show that long line should be split in Fun Or Property: after EQ (between head and body this function)\n     */\n    private class FunAndProperty(node: ASTNode) : LongLineFixableCases(node) {\n        override fun fix() {\n            node.appendNewlineMergingWhiteSpace(null, node.findChildByType(EQ)?.treeNext)\n        }\n\n        override fun unFix() {\n            node.findChildAfter(EQ, WHITE_SPACE)?.let { correctWhiteSpace ->\n                if (correctWhiteSpace.textContains('\\n')) {\n                    correctWhiteSpace.nextSibling()?.let { wrongWhiteSpace ->\n                        if (wrongWhiteSpace.textContains('\\n')) {\n                            node.removeChild(wrongWhiteSpace)\n                        }\n                    }\n                }\n            }\n        }\n    }\n\n    /**\n     * Class Lambda show that long line should be split in Lambda: in space after [LBRACE] node and before [RBRACE] node\n     */\n    private class Lambda(node: ASTNode) : LongLineFixableCases(node) {\n        /**\n         * Splits Lambda expressions - add splits lines, thereby making the lambda expression a separate line\n         */\n        override fun fix() {\n            node.appendNewlineMergingWhiteSpace(node.findChildByType(LBRACE)?.treeNext, node.findChildByType(LBRACE)?.treeNext)\n            node.appendNewlineMergingWhiteSpace(node.findChildByType(RBRACE)?.treePrev, node.findChildByType(RBRACE)?.treePrev)\n        }\n    }\n\n    /**\n     * Class DotQualifiedExpression show that line should be split in DotQualifiedExpression\n     */\n    private class DotQualifiedExpression(node: ASTNode) : LongLineFixableCases(node) {\n        override fun fix() {\n            val dot = node.getFirstChildWithType(DOT)\n            val safeAccess = node.getFirstChildWithType(SAFE_ACCESS)\n            val splitNode = if ((dot?.startOffset ?: 0) > (safeAccess?.startOffset ?: 0)) {\n                dot\n            } else {\n                safeAccess\n            }\n            val nodeBeforeDot = splitNode?.treePrev\n            node.appendNewlineMergingWhiteSpace(nodeBeforeDot, splitNode)\n        }\n    }\n\n    /**\n     * Class ValueArgumentList show that line should be split in ValueArgumentList:\n     * @property maximumLineLength - max line length\n     * @property positionByOffset\n     */\n    private class ValueArgumentList(\n        node: ASTNode,\n        val maximumLineLength: LineLengthConfiguration,\n        var positionByOffset: (Int) -> Pair<Int, Int>\n    ) : LongLineFixableCases(node) {\n        override fun fix() {\n            val lineLength = maximumLineLength.lineLength\n            val offset = fixFirst()\n            val listComma = node.getAllChildrenWithType(COMMA).map {\n                it to positionByOffset(it.startOffset - offset).second\n            }.sortedBy { it.second }\n            var lineNumber = 1\n            listComma.forEachIndexed { index, pair ->\n                if (pair.second >= lineNumber * lineLength) {\n                    lineNumber++\n                    val commaSplit = if (index > 0) {\n                        listComma[index - 1].first\n                    } else {\n                        pair.first\n                    }\n                    node.appendNewlineMergingWhiteSpace(commaSplit.treeNext, commaSplit.treeNext)\n                }\n            }\n            node.getFirstChildWithType(RPAR)?.let { child ->\n                if (positionByOffset(child.treePrev.startOffset).second + child.treePrev.text.length - offset > lineLength * lineNumber && listComma.isNotEmpty()) {\n                    listComma.last().first.let {\n                        node.appendNewlineMergingWhiteSpace(it.treeNext, it.treeNext)\n                    }\n                }\n            }\n        }\n\n        override fun unFix() {\n            node.findChildBefore(RPAR, WHITE_SPACE)?.let { correctWhiteSpace ->\n                if (correctWhiteSpace.textContains('\\n')) {\n                    correctWhiteSpace.prevSibling()?.let { wrongWhiteSpace ->\n                        if (wrongWhiteSpace.textContains('\\n')) {\n                            node.removeChild(wrongWhiteSpace)\n                        }\n                    }\n                }\n            }\n        }\n\n        private fun fixFirst(): Int {\n            val lineLength = maximumLineLength.lineLength\n            var startOffset = 0\n            node.getFirstChildWithType(COMMA)?.let {\n                if (positionByOffset(it.startOffset).second > lineLength) {\n                    node.appendNewlineMergingWhiteSpace(node.findChildByType(LPAR)?.treeNext, node.findChildByType(LPAR)?.treeNext)\n                    node.appendNewlineMergingWhiteSpace(node.findChildByType(RPAR), node.findChildByType(RPAR))\n                    startOffset = this.maximumLineLength.lineLength.toInt()\n                }\n            } ?: node.getFirstChildWithType(RPAR)?.let {\n                node.appendNewlineMergingWhiteSpace(node.findChildByType(LPAR)?.treeNext, node.findChildByType(LPAR)?.treeNext)\n                node.appendNewlineMergingWhiteSpace(node.findChildByType(RPAR), node.findChildByType(RPAR))\n                startOffset = this.maximumLineLength.lineLength.toInt()\n            }\n            return startOffset\n        }\n    }\n\n    /**\n     * Class WhenEntry show that line should be split in WhenEntry node:\n     * - Added [LBRACE] and [RBRACE] nodes\n     * - Split line in space after [LBRACE] node and before [RBRACE] node\n     */\n    private class WhenEntry(node: ASTNode) : LongLineFixableCases(node) {\n        override fun fix() {\n            node.getFirstChildWithType(ARROW)?.let {\n                node.appendNewlineMergingWhiteSpace(it.treeNext, it.treeNext)\n            }\n        }\n    }\n\n    companion object {\n        private val log = KotlinLogging.logger {}\n        private const val MAX_FIX_NUMBER = 10\n        private const val MAX_LENGTH = 120L\n        const val NAME_ID = \"line-length\"\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/main/kotlin/com/saveourtool/diktat/ruleset/rules/chapter3/LongNumericalValuesSeparatedRule.kt",
    "content": "package com.saveourtool.diktat.ruleset.rules.chapter3\n\nimport com.saveourtool.diktat.common.config.rules.RuleConfiguration\nimport com.saveourtool.diktat.common.config.rules.RulesConfig\nimport com.saveourtool.diktat.common.config.rules.getRuleConfig\nimport com.saveourtool.diktat.ruleset.constants.Warnings.LONG_NUMERICAL_VALUES_SEPARATED\nimport com.saveourtool.diktat.ruleset.rules.DiktatRule\n\nimport org.jetbrains.kotlin.com.intellij.lang.ASTNode\nimport org.jetbrains.kotlin.com.intellij.psi.impl.source.tree.LeafPsiElement\nimport org.jetbrains.kotlin.lexer.KtTokens.FLOAT_LITERAL\nimport org.jetbrains.kotlin.lexer.KtTokens.INTEGER_LITERAL\n\nimport java.lang.StringBuilder\n\n/**\n * Rule that checks if numerical separators (`_`) are used for long numerical literals\n */\nclass LongNumericalValuesSeparatedRule(configRules: List<RulesConfig>) : DiktatRule(\n    NAME_ID,\n    configRules,\n    listOf(LONG_NUMERICAL_VALUES_SEPARATED)\n) {\n    override fun logic(node: ASTNode) {\n        val configuration = LongNumericalValuesConfiguration(\n            configRules.getRuleConfig(LONG_NUMERICAL_VALUES_SEPARATED)?.configuration ?: emptyMap())\n\n        if (node.elementType == INTEGER_LITERAL && !isValidConstant(node.text, configuration, node)) {\n            LONG_NUMERICAL_VALUES_SEPARATED.warnAndFix(configRules, emitWarn, isFixMode, node.text, node.startOffset, node) {\n                fixIntegerConstant(node, configuration.maxBlockLength)\n            }\n        }\n\n        if (node.elementType == FLOAT_LITERAL && !isValidConstant(node.text, configuration, node)) {\n            val parts = node.text.split(\".\")\n            LONG_NUMERICAL_VALUES_SEPARATED.warnAndFix(configRules, emitWarn, isFixMode, node.text, node.startOffset, node) {\n                fixFloatConstantPart(parts[0], parts[1], configuration, node)\n            }\n        }\n    }\n\n    private fun fixIntegerConstant(node: ASTNode, maxBlockLength: Int) {\n        val resultRealPart = StringBuilder(nodePrefix(node.text))\n\n        val chunks = removePrefixSuffix(node.text)\n            .reversed()\n            .chunked(maxBlockLength)\n            .reversed()\n        resultRealPart.append(chunks.joinToString(separator = \"_\") { it.reversed() })\n\n        resultRealPart.append(nodeSuffix(node.text))\n        (node as LeafPsiElement).rawReplaceWithText(resultRealPart.toString())\n    }\n\n    private fun fixFloatConstantPart(\n        realPart: String,\n        fractionalPart: String,\n        configuration: LongNumericalValuesConfiguration,\n        node: ASTNode\n    ) {\n        val resultRealPart = StringBuilder(nodePrefix(realPart))\n        val resultFractionalPart = StringBuilder()\n\n        val realNumber = removePrefixSuffix(realPart)\n        if (realNumber.length > configuration.maxLength) {\n            val chunks = realNumber\n                .reversed()\n                .chunked(configuration.maxBlockLength)\n                .reversed()\n            resultRealPart.append(chunks.joinToString(separator = \"_\") { it.reversed() })\n\n            resultRealPart.append(nodeSuffix(realPart)).append(\".\")\n        } else {\n            resultRealPart.append(realNumber).append(\".\")\n        }\n\n        val fractionalNumber = removePrefixSuffix(fractionalPart)\n        if (fractionalNumber.length > configuration.maxLength) {\n            val chunks = fractionalNumber.chunked(configuration.maxBlockLength)\n            resultFractionalPart.append(chunks.joinToString(separator = \"_\", postfix = nodeSuffix(fractionalPart)) { it })\n\n            resultFractionalPart.append(nodeSuffix(fractionalPart))\n        } else {\n            resultFractionalPart.append(fractionalNumber).append(nodeSuffix(fractionalPart))\n        }\n\n        (node as LeafPsiElement).rawReplaceWithText(resultRealPart.append(resultFractionalPart).toString())\n    }\n\n    private fun nodePrefix(nodeText: String) = when {\n        nodeText.startsWith(\"0b\") -> \"0b\"\n        nodeText.startsWith(\"0x\") -> \"0x\"\n        else -> \"\"\n    }\n\n    private fun nodeSuffix(nodeText: String) = when {\n        nodeText.endsWith(\"L\") -> \"L\"\n        nodeText.endsWith(\"f\", true) -> \"f\"\n        else -> \"\"\n    }\n\n    private fun isValidConstant(\n        text: String,\n        configuration: LongNumericalValuesConfiguration,\n        node: ASTNode\n    ): Boolean {\n        if (text.contains(\"_\")) {\n            checkBlocks(removePrefixSuffix(text), configuration, node)\n            return true\n        }\n\n        return text\n            .split(\".\")\n            .map { removePrefixSuffix(it) }\n            .all { it.length <= configuration.maxLength }\n    }\n\n    private fun checkBlocks(\n        text: String,\n        configuration: LongNumericalValuesConfiguration,\n        node: ASTNode\n    ) {\n        val blocks = text.split(\"_\", \".\")\n\n        blocks.forEach {\n            if (it.length > configuration.maxBlockLength) {\n                LONG_NUMERICAL_VALUES_SEPARATED.warn(configRules, emitWarn, \"this block is too long $it\", node.startOffset, node)\n            }\n        }\n    }\n\n    private fun removePrefixSuffix(text: String): String {\n        if (text.startsWith(\"0x\")) {\n            return text.removePrefix(\"0x\")\n        }\n\n        return text.removePrefix(\"0b\")\n            .removeSuffix(\"L\")\n            .removeSuffix(\"f\")\n            .removeSuffix(\"F\")\n    }\n\n    /**\n     * [RuleConfiguration] for numerical literals separation\n     */\n    class LongNumericalValuesConfiguration(config: Map<String, String>) : RuleConfiguration(config) {\n        /**\n         * Maximum number of digits which are not split\n         */\n        val maxLength = config[\"maxNumberLength\"]?.toIntOrNull() ?: MAX_NUMBER_LENGTH\n\n        /**\n         * Maximum number of digits between separators\n         */\n        val maxBlockLength = config[\"maxBlockLength\"]?.toIntOrNull() ?: DELIMITER_LENGTH\n    }\n\n    companion object {\n        private const val DELIMITER_LENGTH: Int = 3\n        private const val MAX_NUMBER_LENGTH: Int = 3\n        const val NAME_ID = \"long-numerical-values\"\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/main/kotlin/com/saveourtool/diktat/ruleset/rules/chapter3/MagicNumberRule.kt",
    "content": "package com.saveourtool.diktat.ruleset.rules.chapter3\n\nimport com.saveourtool.diktat.common.config.rules.RuleConfiguration\nimport com.saveourtool.diktat.common.config.rules.RulesConfig\nimport com.saveourtool.diktat.common.config.rules.getCommonConfiguration\nimport com.saveourtool.diktat.common.config.rules.getRuleConfig\nimport com.saveourtool.diktat.ruleset.constants.Warnings.MAGIC_NUMBER\nimport com.saveourtool.diktat.ruleset.rules.DiktatRule\nimport com.saveourtool.diktat.ruleset.utils.*\nimport com.saveourtool.diktat.ruleset.utils.parent\n\nimport org.jetbrains.kotlin.KtNodeTypes.BINARY_EXPRESSION\nimport org.jetbrains.kotlin.KtNodeTypes.ENUM_ENTRY\nimport org.jetbrains.kotlin.KtNodeTypes.FLOAT_CONSTANT\nimport org.jetbrains.kotlin.KtNodeTypes.FUN\nimport org.jetbrains.kotlin.KtNodeTypes.INTEGER_CONSTANT\nimport org.jetbrains.kotlin.KtNodeTypes.OPERATION_REFERENCE\nimport org.jetbrains.kotlin.KtNodeTypes.PROPERTY\nimport org.jetbrains.kotlin.KtNodeTypes.VALUE_PARAMETER\nimport org.jetbrains.kotlin.com.intellij.lang.ASTNode\nimport org.jetbrains.kotlin.lexer.KtTokens.IDENTIFIER\nimport org.jetbrains.kotlin.lexer.KtTokens.MINUS\nimport org.jetbrains.kotlin.lexer.KtTokens.RANGE\nimport org.jetbrains.kotlin.psi.KtFunction\nimport org.jetbrains.kotlin.psi.KtProperty\nimport org.jetbrains.kotlin.psi.psiUtil.isExtensionDeclaration\nimport org.jetbrains.kotlin.psi.psiUtil.parents\n\n/**\n * Rule for magic number\n */\nclass MagicNumberRule(configRules: List<RulesConfig>) : DiktatRule(\n    NAME_ID,\n    configRules,\n    listOf(MAGIC_NUMBER)\n) {\n    private val configuration by lazy {\n        MagicNumberConfiguration(\n            configRules.getRuleConfig(MAGIC_NUMBER)?.configuration ?: emptyMap()\n        )\n    }\n    @Suppress(\"COLLAPSE_IF_STATEMENTS\")\n    override fun logic(node: ASTNode) {\n        val filePath = node.getFilePath()\n        val config = configRules.getCommonConfiguration()\n        if (node.elementType == INTEGER_CONSTANT || node.elementType == FLOAT_CONSTANT) {\n            if (!isLocatedInTest(filePath.splitPathToDirs(), config.testAnchors) || !configuration.isIgnoreTest) {\n                checkNumber(node, configuration)\n            }\n        }\n    }\n\n    @Suppress(\"ComplexMethod\")\n    private fun checkNumber(node: ASTNode, configuration: MagicNumberConfiguration) {\n        val nodeText = node.treePrev?.let { if (it.elementType == OPERATION_REFERENCE && it.hasChildOfType(MINUS)) \"-${node.text}\" else node.text } ?: node.text\n\n        val isIgnoreNumber = configuration.ignoreNumbers.contains(nodeText)\n\n        val isHashFunction = node.parent { it.elementType == FUN && it.isHashFun() } != null\n        val isLocalVariable = node.parent { it.elementType == PROPERTY && (it.isVarProperty() || it.isValProperty()) && (it.psi as KtProperty).isLocal } != null\n        val isValueParameter = node.parent { it.elementType == VALUE_PARAMETER } != null\n        val isConstant = node.parent { it.elementType == PROPERTY && it.isConstant() } != null\n        val isCompanionObjectProperty = node.parent { it.elementType == PROPERTY && it.isNodeFromCompanionObject() } != null\n        val isEnums = node.parent { it.elementType == ENUM_ENTRY } != null\n        val isRanges = node.treeParent.let {\n            it.elementType == BINARY_EXPRESSION && it.findChildByType(OPERATION_REFERENCE)?.hasChildOfType(RANGE) ?: false\n        }\n        val isExtensionFunctions = node.parent { it.elementType == FUN && (it.psi as KtFunction).isExtensionDeclaration() } != null &&\n                node.parents().none { it.elementType == PROPERTY }\n        val isPairsCreatedUsingTo = node.treeParent.let {\n            it.elementType == BINARY_EXPRESSION && it.findChildByType(OPERATION_REFERENCE)?.findChildByType(IDENTIFIER)?.text == \"to\"\n        }\n        val isPropertyDeclaration = !isLocalVariable && !isConstant && !isCompanionObjectProperty && !isRanges && !isPairsCreatedUsingTo &&\n                node.parent { it.elementType == PROPERTY } != null\n\n        val result = listOf(isHashFunction, isPropertyDeclaration, isLocalVariable, isValueParameter, isConstant, isCompanionObjectProperty, isEnums, isRanges,\n            isExtensionFunctions, isPairsCreatedUsingTo).zip(mapConfiguration.map { configuration.getParameter(it.key) })\n\n        if (result.any { it.first && !it.second } && !isIgnoreNumber) {\n            MAGIC_NUMBER.warn(configRules, emitWarn, nodeText, node.startOffset, node)\n        }\n    }\n\n    private fun ASTNode.isHashFun() =\n        (this.psi as KtFunction).run {\n            this.nameIdentifier?.text == \"hashCode\" && this.annotationEntries.map { it.text }.contains(\"@Override\")\n        }\n\n    /**\n     * [RuleConfiguration] for configuration\n     */\n    class MagicNumberConfiguration(config: Map<String, String>) : RuleConfiguration(config) {\n        /**\n         * Flag to ignore numbers from test\n         */\n        val isIgnoreTest = config[\"ignoreTest\"]?.toBoolean() ?: IGNORE_TEST\n\n        /**\n         * List of ignored numbers\n         */\n        val ignoreNumbers = config[\"ignoreNumbers\"]?.split(\",\")?.map { it.trim() }?.filter { it.isNumber() || it.isOtherNumberType() } ?: ignoreNumbersList\n\n        /**\n         * @param param parameter from config\n         * @return value of parameter\n         */\n        @Suppress(\"UnsafeCallOnNullableType\")\n        fun getParameter(param: String) = config[param]?.toBoolean() ?: mapConfiguration[param]!!\n\n        /**\n         * Check if string is number\n         */\n        // || ((this.last().uppercase() == \"L\" || this.last().uppercase() == \"U\") && this.substring(0, this.lastIndex-1).isNumber())\n        private fun String.isNumber() = (this.toLongOrNull() ?: this.toFloatOrNull()) != null\n\n        /**\n         * Check if string include a char of number type\n         */\n        private fun String.isOtherNumberType(): Boolean = ((this.last().uppercase() == \"L\" || this.last().uppercase() == \"U\") && this.substring(0, this.lastIndex).isNumber()) ||\n                (this.substring(this.lastIndex - 1).uppercase() == \"UL\" && this.substring(0, this.lastIndex - 1).isNumber())\n    }\n\n    companion object {\n        const val IGNORE_TEST = true\n        const val NAME_ID = \"magic-number\"\n        val ignoreNumbersList = listOf(\"-1\", \"1\", \"0\", \"2\", \"0U\", \"1U\", \"2U\", \"-1L\", \"0L\", \"1L\", \"2L\", \"0UL\", \"1UL\", \"2UL\")\n        val mapConfiguration = mapOf(\n            \"ignoreHashCodeFunction\" to true,\n            \"ignorePropertyDeclaration\" to false,\n            \"ignoreLocalVariableDeclaration\" to false,\n            \"ignoreValueParameter\" to true,\n            \"ignoreConstantDeclaration\" to true,\n            \"ignoreCompanionObjectPropertyDeclaration\" to true,\n            \"ignoreEnums\" to false,\n            \"ignoreRanges\" to false,\n            \"ignoreExtensionFunctions\" to false,\n            \"ignorePairsCreatedUsingTo\" to false)\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/main/kotlin/com/saveourtool/diktat/ruleset/rules/chapter3/MultipleModifiersSequence.kt",
    "content": "package com.saveourtool.diktat.ruleset.rules.chapter3\n\nimport com.saveourtool.diktat.common.config.rules.RulesConfig\nimport com.saveourtool.diktat.ruleset.constants.Warnings.WRONG_MULTIPLE_MODIFIERS_ORDER\nimport com.saveourtool.diktat.ruleset.rules.DiktatRule\nimport com.saveourtool.diktat.ruleset.utils.findAllDescendantsWithSpecificType\n\nimport org.jetbrains.kotlin.KtNodeTypes.ANNOTATION_ENTRY\nimport org.jetbrains.kotlin.KtNodeTypes.FUN\nimport org.jetbrains.kotlin.KtNodeTypes.MODIFIER_LIST\nimport org.jetbrains.kotlin.com.intellij.lang.ASTNode\nimport org.jetbrains.kotlin.com.intellij.psi.impl.source.tree.PsiWhiteSpaceImpl\nimport org.jetbrains.kotlin.lexer.KtTokens\nimport org.jetbrains.kotlin.lexer.KtTokens.FUN_KEYWORD\nimport org.jetbrains.kotlin.lexer.KtTokens.WHITE_SPACE\nimport org.jetbrains.kotlin.psi.KtClass\nimport org.jetbrains.kotlin.psi.psiUtil.children\n\n/**\n * @param configRules\n */\nclass MultipleModifiersSequence(configRules: List<RulesConfig>) : DiktatRule(\n    NAME_ID,\n    configRules,\n    listOf(WRONG_MULTIPLE_MODIFIERS_ORDER)\n) {\n    override fun logic(node: ASTNode) {\n        if (node.elementType == MODIFIER_LIST) {\n            checkModifierList(node)\n            checkAnnotation(node)\n        }\n    }\n\n    private fun checkModifierList(node: ASTNode) {\n        val modifierListOfPair = node\n            .getChildren(KtTokens.MODIFIER_KEYWORDS)\n            .toList()\n            .filter {\n                !isSamInterfaces(node, it)\n            }\n            .map { Pair(it, modifierOrder.indexOf(it.elementType)) }\n        val sortModifierListOfPair = modifierListOfPair.sortedBy { it.second }.map { it.first }\n        modifierListOfPair.forEachIndexed { index, (modifierNode, _) ->\n            if (modifierNode != sortModifierListOfPair[index]) {\n                WRONG_MULTIPLE_MODIFIERS_ORDER.warnAndFix(configRules, emitWarn, isFixMode,\n                    \"${modifierNode.text} should be on position ${sortModifierListOfPair.indexOf(modifierNode) + 1}, but is on position ${index + 1}\",\n                    modifierNode.startOffset, modifierNode) {\n                    val nodeAfter = modifierNode.treeNext\n                    node.removeChild(modifierNode)\n                    node.addChild((sortModifierListOfPair[index].clone() as ASTNode), nodeAfter)\n                }\n            }\n        }\n    }\n\n    private fun isSamInterfaces(parent: ASTNode, node: ASTNode): Boolean {\n        val parentPsi = parent.treeParent.psi\n        return if (parentPsi is KtClass) {\n            (parentPsi.isInterface()) && node.elementType == FUN_KEYWORD && parent.treeParent.findAllDescendantsWithSpecificType(FUN).size == 1\n        } else {\n            false\n        }\n    }\n\n    private fun checkAnnotation(node: ASTNode) {\n        val firstModifierIndex = node\n            .children()\n            .indexOfFirst { it.elementType in KtTokens.MODIFIER_KEYWORDS }\n            .takeIf { it >= 0 } ?: return\n        node\n            .getChildren(null)\n            .filterIndexed { index, astNode -> astNode.elementType == ANNOTATION_ENTRY && index > firstModifierIndex }\n            .forEach { astNode ->\n                WRONG_MULTIPLE_MODIFIERS_ORDER.warnAndFix(configRules, emitWarn, isFixMode,\n                    \"${astNode.text} annotation should be before all modifiers\",\n                    astNode.startOffset, astNode) {\n                    val spaceBefore = astNode.treePrev\n                    node.removeChild(astNode)\n                    if (spaceBefore != null && spaceBefore.elementType == WHITE_SPACE) {\n                        node.removeChild(spaceBefore)\n                        node.addChild(spaceBefore, node.firstChildNode)\n                        node.addChild(astNode.clone() as ASTNode, spaceBefore)\n                    } else {\n                        node.addChild(PsiWhiteSpaceImpl(\" \"), node.getChildren(null).first())\n                        node.addChild(astNode.clone() as ASTNode, node.getChildren(null).first())\n                    }\n                }\n            }\n    }\n\n    companion object {\n        const val NAME_ID = \"multiple-modifiers\"\n        private val modifierOrder = listOf(KtTokens.PUBLIC_KEYWORD, KtTokens.INTERNAL_KEYWORD, KtTokens.PROTECTED_KEYWORD,\n            KtTokens.PRIVATE_KEYWORD, KtTokens.EXPECT_KEYWORD, KtTokens.ACTUAL_KEYWORD, KtTokens.FINAL_KEYWORD,\n            KtTokens.OPEN_KEYWORD, KtTokens.ABSTRACT_KEYWORD, KtTokens.SEALED_KEYWORD, KtTokens.CONST_KEYWORD,\n            KtTokens.EXTERNAL_KEYWORD, KtTokens.OVERRIDE_KEYWORD, KtTokens.LATEINIT_KEYWORD, KtTokens.TAILREC_KEYWORD,\n            KtTokens.CROSSINLINE_KEYWORD, KtTokens.VARARG_KEYWORD, KtTokens.SUSPEND_KEYWORD, KtTokens.INNER_KEYWORD,\n            KtTokens.OUT_KEYWORD, KtTokens.ENUM_KEYWORD, KtTokens.ANNOTATION_KEYWORD, KtTokens.COMPANION_KEYWORD,\n            KtTokens.VALUE_KEYWORD, KtTokens.INLINE_KEYWORD, KtTokens.NOINLINE_KEYWORD, KtTokens.REIFIED_KEYWORD, KtTokens.INFIX_KEYWORD,\n            KtTokens.OPERATOR_KEYWORD, KtTokens.DATA_KEYWORD, KtTokens.IN_KEYWORD)\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/main/kotlin/com/saveourtool/diktat/ruleset/rules/chapter3/NullableTypeRule.kt",
    "content": "package com.saveourtool.diktat.ruleset.rules.chapter3\n\nimport com.saveourtool.diktat.common.config.rules.RulesConfig\nimport com.saveourtool.diktat.ruleset.constants.Warnings.NULLABLE_PROPERTY_TYPE\nimport com.saveourtool.diktat.ruleset.rules.DiktatRule\nimport com.saveourtool.diktat.ruleset.utils.KotlinParser\nimport com.saveourtool.diktat.ruleset.utils.findAllDescendantsWithSpecificType\nimport com.saveourtool.diktat.ruleset.utils.hasChildOfType\n\nimport org.jetbrains.kotlin.KtNodeTypes.BOOLEAN_CONSTANT\nimport org.jetbrains.kotlin.KtNodeTypes.CALL_EXPRESSION\nimport org.jetbrains.kotlin.KtNodeTypes.CHARACTER_CONSTANT\nimport org.jetbrains.kotlin.KtNodeTypes.DOT_QUALIFIED_EXPRESSION\nimport org.jetbrains.kotlin.KtNodeTypes.FLOAT_CONSTANT\nimport org.jetbrains.kotlin.KtNodeTypes.INTEGER_CONSTANT\nimport org.jetbrains.kotlin.KtNodeTypes.NULL\nimport org.jetbrains.kotlin.KtNodeTypes.NULLABLE_TYPE\nimport org.jetbrains.kotlin.KtNodeTypes.PROPERTY\nimport org.jetbrains.kotlin.KtNodeTypes.REFERENCE_EXPRESSION\nimport org.jetbrains.kotlin.KtNodeTypes.STRING_TEMPLATE\nimport org.jetbrains.kotlin.KtNodeTypes.TYPE_REFERENCE\nimport org.jetbrains.kotlin.KtNodeTypes.USER_TYPE\nimport org.jetbrains.kotlin.com.intellij.lang.ASTNode\nimport org.jetbrains.kotlin.com.intellij.psi.impl.source.tree.CompositeElement\nimport org.jetbrains.kotlin.com.intellij.psi.impl.source.tree.LeafPsiElement\nimport org.jetbrains.kotlin.com.intellij.psi.tree.IElementType\nimport org.jetbrains.kotlin.lexer.KtTokens.CHARACTER_LITERAL\nimport org.jetbrains.kotlin.lexer.KtTokens.CLOSING_QUOTE\nimport org.jetbrains.kotlin.lexer.KtTokens.EQ\nimport org.jetbrains.kotlin.lexer.KtTokens.FLOAT_LITERAL\nimport org.jetbrains.kotlin.lexer.KtTokens.INTEGER_LITERAL\nimport org.jetbrains.kotlin.lexer.KtTokens.OPEN_QUOTE\nimport org.jetbrains.kotlin.lexer.KtTokens.QUEST\nimport org.jetbrains.kotlin.lexer.KtTokens.TRUE_KEYWORD\nimport org.jetbrains.kotlin.lexer.KtTokens.VAL_KEYWORD\n\n/**\n * Rule that checks if nullable types are used and suggest to substitute them with non-nullable\n */\nclass NullableTypeRule(configRules: List<RulesConfig>) : DiktatRule(\n    NAME_ID,\n    configRules,\n    listOf(NULLABLE_PROPERTY_TYPE)\n) {\n    override fun logic(node: ASTNode) {\n        if (node.elementType == PROPERTY) {\n            checkProperty(node)\n        }\n    }\n\n    @Suppress(\"UnsafeCallOnNullableType\")\n    private fun checkProperty(node: ASTNode) {\n        if (node.hasChildOfType(VAL_KEYWORD) && node.hasChildOfType(EQ) && node.hasChildOfType(TYPE_REFERENCE)) {\n            val typeReferenceNode = node.findChildByType(TYPE_REFERENCE)!!\n            // check that property has nullable type, right value one of allow expression\n            if (!node.hasChildOfType(NULL) &&\n                    node.findAllDescendantsWithSpecificType(DOT_QUALIFIED_EXPRESSION).isEmpty() &&\n                    typeReferenceNode.hasChildOfType(NULLABLE_TYPE) &&\n                    typeReferenceNode.findChildByType(NULLABLE_TYPE)!!.hasChildOfType(QUEST) &&\n                    (node.findChildByType(CALL_EXPRESSION)?.findChildByType(REFERENCE_EXPRESSION) == null ||\n                            node.findChildByType(CALL_EXPRESSION)!!.findChildByType(REFERENCE_EXPRESSION)!!.text in allowExpression)) {\n                NULLABLE_PROPERTY_TYPE.warn(configRules, emitWarn, \"don't use nullable type\",\n                    node.findChildByType(TYPE_REFERENCE)!!.startOffset, node)\n            } else if (node.hasChildOfType(NULL)) {\n                val fixedParam = findFixableParam(node)\n                NULLABLE_PROPERTY_TYPE.warnOnlyOrWarnAndFix(configRules, emitWarn, \"initialize explicitly\",\n                    node.findChildByType(NULL)!!.startOffset, node, shouldBeAutoCorrected = fixedParam != null, isFixMode) {\n                    fixedParam?.let {\n                        findSubstitution(node, fixedParam)\n                    }\n                }\n            }\n        }\n    }\n\n    @Suppress(\"UnsafeCallOnNullableType\")\n    private fun findFixableParam(node: ASTNode): FixedParam? {\n        val reference = node.findChildByType(TYPE_REFERENCE)!!\n            .findChildByType(NULLABLE_TYPE)!!\n            .findChildByType(USER_TYPE)\n            ?.findChildByType(REFERENCE_EXPRESSION)\n            ?: return null\n        return when (reference.text) {\n            \"Boolean\" -> FixedParam(BOOLEAN_CONSTANT, TRUE_KEYWORD, \"true\")\n            \"Int\", \"Short\", \"Byte\" -> FixedParam(INTEGER_CONSTANT, INTEGER_LITERAL, \"0\")\n            \"Double\" -> FixedParam(FLOAT_CONSTANT, FLOAT_LITERAL, \"0.0\")\n            \"Float\" -> FixedParam(FLOAT_CONSTANT, FLOAT_LITERAL, \"0.0F\")\n            \"Long\" -> FixedParam(INTEGER_CONSTANT, INTEGER_LITERAL, \"0L\")\n            \"Char\" -> FixedParam(CHARACTER_CONSTANT, CHARACTER_LITERAL, \"''\")\n            \"String\" -> FixedParam(null, null, \"\", true)\n            else -> findFixableForCollectionParam(reference.text)\n        }\n    }\n\n    private fun findFixableForCollectionParam(referenceText: String): FixedParam? =\n        when (referenceText) {\n            \"List\", \"Iterable\" -> FixedParam(null, null, \"emptyList()\")\n            \"Map\" -> FixedParam(null, null, \"emptyMap()\")\n            \"Array\" -> FixedParam(null, null, \"emptyArray()\")\n            \"Set\" -> FixedParam(null, null, \"emptySet()\")\n            \"Sequence\" -> FixedParam(null, null, \"emptySequence()\")\n            \"Queue\" -> FixedParam(null, null, \"LinkedList()\")\n            \"MutableList\" -> FixedParam(null, null, \"mutableListOf()\")\n            \"MutableMap\" -> FixedParam(null, null, \"mutableMapOf()\")\n            \"MutableSet\" -> FixedParam(null, null, \"mutableSetOf()\")\n            \"LinkedList\" -> FixedParam(null, null, \"LinkedList()\")\n            \"LinkedHashMap\" -> FixedParam(null, null, \"LinkedHashMap()\")\n            \"LinkedHashSet\" -> FixedParam(null, null, \"LinkedHashSet()\")\n            else -> null\n        }\n\n    @Suppress(\"UnsafeCallOnNullableType\")\n    private fun findSubstitution(node: ASTNode, fixedParam: FixedParam) {\n        if (fixedParam.isString) {\n            replaceValueForString(node)\n        } else if (fixedParam.insertConstantType != null && fixedParam.insertType != null) {\n            replaceValue(node, fixedParam.insertConstantType, fixedParam.insertType, fixedParam.textNode)\n        } else {\n            replaceValueByText(node, fixedParam.textNode)\n        }\n        val nullableNode = node.findChildByType(TYPE_REFERENCE)!!.findChildByType(NULLABLE_TYPE)!!\n        val userTypeNode = nullableNode.firstChildNode\n        node.findChildByType(TYPE_REFERENCE)!!.replaceChild(nullableNode, userTypeNode)\n    }\n\n    @Suppress(\"UnsafeCallOnNullableType\")\n    private fun replaceValueByText(node: ASTNode, nodeText: String) {\n        val newNode = KotlinParser().createNode(nodeText)\n        if (newNode.elementType == CALL_EXPRESSION) {\n            node.replaceChild(node.findChildByType(NULL)!!, newNode)\n        }\n    }\n\n    @Suppress(\"UnsafeCallOnNullableType\")\n    private fun replaceValue(\n        node: ASTNode,\n        insertConstantType: IElementType,\n        insertType: IElementType,\n        textNode: String\n    ) {\n        val value = CompositeElement(insertConstantType)\n        node.addChild(value, node.findChildByType(NULL)!!)\n        node.removeChild(node.findChildByType(NULL)!!)\n        value.addChild(LeafPsiElement(insertType, textNode))\n    }\n\n    @Suppress(\"UnsafeCallOnNullableType\")\n    private fun replaceValueForString(node: ASTNode) {\n        val value = CompositeElement(STRING_TEMPLATE)\n        node.addChild(value, node.findChildByType(NULL)!!)\n        node.removeChild(node.findChildByType(NULL)!!)\n        value.addChild(LeafPsiElement(OPEN_QUOTE, \"\"))\n        value.addChild(LeafPsiElement(CLOSING_QUOTE, \"\"))\n    }\n\n    @Suppress(\"KDOC_NO_CONSTRUCTOR_PROPERTY\")  // todo add proper docs\n    private data class FixedParam(\n        val insertConstantType: IElementType?,\n        val insertType: IElementType?,\n        val textNode: String,\n        val isString: Boolean = false\n    )\n\n    companion object {\n        const val NAME_ID = \"nullable-type\"\n        private val allowExpression = listOf(\"emptyList\", \"emptySequence\", \"emptyArray\", \"emptyMap\", \"emptySet\",\n            \"listOf\", \"mapOf\", \"arrayOf\", \"sequenceOf\", \"setOf\")\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/main/kotlin/com/saveourtool/diktat/ruleset/rules/chapter3/PreviewAnnotationRule.kt",
    "content": "package com.saveourtool.diktat.ruleset.rules.chapter3\n\nimport com.saveourtool.diktat.common.config.rules.RulesConfig\nimport com.saveourtool.diktat.ruleset.constants.Warnings.PREVIEW_ANNOTATION\nimport com.saveourtool.diktat.ruleset.rules.DiktatRule\nimport com.saveourtool.diktat.ruleset.utils.KotlinParser\nimport com.saveourtool.diktat.ruleset.utils.findAllNodesWithCondition\nimport com.saveourtool.diktat.ruleset.utils.getAllChildrenWithType\nimport com.saveourtool.diktat.ruleset.utils.getIdentifierName\n\nimport org.jetbrains.kotlin.KtNodeTypes.ANNOTATION_ENTRY\nimport org.jetbrains.kotlin.KtNodeTypes.FUN\nimport org.jetbrains.kotlin.KtNodeTypes.MODIFIER_LIST\nimport org.jetbrains.kotlin.com.intellij.lang.ASTFactory\nimport org.jetbrains.kotlin.com.intellij.lang.ASTNode\nimport org.jetbrains.kotlin.lexer.KtTokens\nimport org.jetbrains.kotlin.lexer.KtTokens.ABSTRACT_KEYWORD\nimport org.jetbrains.kotlin.lexer.KtTokens.INTERNAL_KEYWORD\nimport org.jetbrains.kotlin.lexer.KtTokens.OPEN_KEYWORD\nimport org.jetbrains.kotlin.lexer.KtTokens.PRIVATE_KEYWORD\nimport org.jetbrains.kotlin.lexer.KtTokens.PROTECTED_KEYWORD\nimport org.jetbrains.kotlin.lexer.KtTokens.PUBLIC_KEYWORD\nimport org.jetbrains.kotlin.lexer.KtTokens.WHITE_SPACE\nimport org.jetbrains.kotlin.psi.KtNamedFunction\nimport org.jetbrains.kotlin.psi.psiUtil.isPrivate\n\n/**\n * This rule checks, whether the method has `@Preview` annotation (Jetpack Compose)\n * If so, such method should be private and function name should end with `Preview` suffix\n */\nclass PreviewAnnotationRule(configRules: List<RulesConfig>) : DiktatRule(\n    NAME_ID,\n    configRules,\n    listOf(PREVIEW_ANNOTATION)\n) {\n    override fun logic(node: ASTNode) {\n        if (node.elementType == FUN) {\n            checkFunctionSignature(node)\n        }\n    }\n\n    private fun checkFunctionSignature(node: ASTNode) {\n        node.findChildByType(MODIFIER_LIST)?.let { modList ->\n            doCheck(node, modList)\n        }\n    }\n\n    @Suppress(\"TOO_LONG_FUNCTION\")\n    private fun doCheck(functionNode: ASTNode, modeList: ASTNode) {\n        if (modeList.getAllChildrenWithType(ANNOTATION_ENTRY).isEmpty()) {\n            return\n        }\n\n        val previewAnnotationNode = modeList.getAllChildrenWithType(ANNOTATION_ENTRY).firstOrNull {\n            it.text.contains(\"$ANNOTATION_SYMBOL$PREVIEW_ANNOTATION_TEXT\")\n        }\n\n        previewAnnotationNode?.let {\n            val functionNameNode = functionNode.getIdentifierName()\n            val functionName = functionNameNode?.text ?: return\n\n            // warn if function is not private\n            if (!(functionNode.psi as KtNamedFunction).isPrivate()) {\n                PREVIEW_ANNOTATION.warnAndFix(\n                    configRules,\n                    emitWarn,\n                    isFixMode,\n                    \"$functionName method should be private\",\n                    functionNode.startOffset,\n                    functionNode\n                ) {\n                    addPrivateModifier(functionNode)\n                }\n            }\n\n            // warn if function has no `Preview` suffix\n            if (!isMethodHasPreviewSuffix(functionName)) {\n                PREVIEW_ANNOTATION.warnAndFix(\n                    configRules,\n                    emitWarn,\n                    isFixMode,\n                    \"$functionName method should has `Preview` suffix\",\n                    functionNode.startOffset,\n                    functionNode\n                ) {\n                    functionNode.replaceChild(\n                        functionNameNode,\n                        KotlinParser().createNode(\"${functionNameNode.text}Preview\")\n                    )\n                }\n            }\n        }\n    }\n\n    private fun isMethodHasPreviewSuffix(functionName: String) =\n        functionName.contains(PREVIEW_ANNOTATION_TEXT)\n\n    private fun addPrivateModifier(functionNode: ASTNode) {\n        // MODIFIER_LIST should be present since ANNOTATION_ENTRY is there\n        val modifierListNode = functionNode.findChildByType(MODIFIER_LIST) ?: return\n        val modifiersList = modifierListNode\n            .getChildren(KtTokens.MODIFIER_KEYWORDS)\n            .toList()\n\n        val isMethodAbstract = modifiersList.any {\n            it.elementType == ABSTRACT_KEYWORD\n        }\n\n        // private modifier is not applicable for abstract methods\n        if (isMethodAbstract) {\n            return\n        }\n\n        // these modifiers could be safely replaced via `private`\n        val modifierForReplacement = modifiersList.firstOrNull {\n            it.elementType in listOf(\n                PUBLIC_KEYWORD, PROTECTED_KEYWORD, INTERNAL_KEYWORD, OPEN_KEYWORD\n            )\n        }\n\n        modifierForReplacement?.let {\n            // replace current modifier with `private`\n            val parent = it.treeParent\n            parent.replaceChild(it, createPrivateModifierNode())\n        } ?: run {\n            // the case, when there is no explicit modifier, i.e. `fun foo`\n            // just add `private` in MODIFIER_LIST at the end\n            // and move WHITE_SPACE before function identifier `fun` to MODIFIER_LIST\n            val funNode = functionNode.findAllNodesWithCondition { it.text == \"fun\" }.single()\n            val whiteSpaceAfterAnnotation = modifierListNode.treeNext\n            modifierListNode.addChild(whiteSpaceAfterAnnotation, null)\n            modifierListNode.addChild(createPrivateModifierNode(), null)\n            // add ` ` node before `fun`\n            functionNode.addChild(ASTFactory.leaf(WHITE_SPACE, \" \"), funNode)\n        }\n    }\n\n    private fun createPrivateModifierNode() = ASTFactory.leaf(PRIVATE_KEYWORD, \"private\")\n\n    companion object {\n        const val ANNOTATION_SYMBOL = \"@\"\n        const val NAME_ID = \"preview-annotation\"\n        const val PREVIEW_ANNOTATION_TEXT = \"Preview\"\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/main/kotlin/com/saveourtool/diktat/ruleset/rules/chapter3/RangeConventionalRule.kt",
    "content": "package com.saveourtool.diktat.ruleset.rules.chapter3\n\nimport com.saveourtool.diktat.common.config.rules.RuleConfiguration\nimport com.saveourtool.diktat.common.config.rules.RulesConfig\nimport com.saveourtool.diktat.common.config.rules.getRuleConfig\nimport com.saveourtool.diktat.ruleset.constants.Warnings.CONVENTIONAL_RANGE\nimport com.saveourtool.diktat.ruleset.rules.DiktatRule\nimport com.saveourtool.diktat.ruleset.utils.KotlinParser\nimport com.saveourtool.diktat.ruleset.utils.getIdentifierName\nimport com.saveourtool.diktat.ruleset.utils.hasChildOfType\nimport com.saveourtool.diktat.ruleset.utils.isWhiteSpace\nimport com.saveourtool.diktat.ruleset.utils.parent\nimport com.saveourtool.diktat.ruleset.utils.takeByChainOfTypes\n\nimport org.jetbrains.kotlin.KtNodeTypes.BINARY_EXPRESSION\nimport org.jetbrains.kotlin.KtNodeTypes.DOT_QUALIFIED_EXPRESSION\nimport org.jetbrains.kotlin.KtNodeTypes.REFERENCE_EXPRESSION\nimport org.jetbrains.kotlin.KtNodeTypes.VALUE_ARGUMENT\nimport org.jetbrains.kotlin.KtNodeTypes.VALUE_ARGUMENT_LIST\nimport org.jetbrains.kotlin.com.intellij.lang.ASTNode\nimport org.jetbrains.kotlin.com.intellij.psi.impl.source.tree.LeafPsiElement\nimport org.jetbrains.kotlin.com.intellij.psi.impl.source.tree.PsiWhiteSpaceImpl\nimport org.jetbrains.kotlin.com.intellij.psi.tree.TokenSet\nimport org.jetbrains.kotlin.lexer.KtTokens.IDENTIFIER\nimport org.jetbrains.kotlin.lexer.KtTokens.INTEGER_LITERAL\nimport org.jetbrains.kotlin.lexer.KtTokens.MINUS\nimport org.jetbrains.kotlin.lexer.KtTokens.RANGE\nimport org.jetbrains.kotlin.psi.KtBinaryExpression\nimport org.jetbrains.kotlin.psi.KtConstantExpression\nimport org.jetbrains.kotlin.psi.KtDotQualifiedExpression\n\n/**\n * This rule warn and fix cases when it's possible to replace range operator `..` with infix function `until`\n * or replace `rangeTo` function with range operator `..`\n */\nclass RangeConventionalRule(configRules: List<RulesConfig>) : DiktatRule(\n    NAME_ID,\n    configRules,\n    listOf(CONVENTIONAL_RANGE)\n) {\n    private val configuration by lazy {\n        RangeConventionalConfiguration(\n            this.configRules.getRuleConfig(CONVENTIONAL_RANGE)?.configuration ?: emptyMap(),\n        )\n    }\n    override fun logic(node: ASTNode) {\n        if (node.elementType == DOT_QUALIFIED_EXPRESSION && !configuration.isRangeToIgnore) {\n            handleQualifiedExpression(node)\n        }\n        if (node.elementType == RANGE) {\n            handleRange(node)\n        }\n    }\n\n    @Suppress(\"TOO_MANY_LINES_IN_LAMBDA\", \"PARAMETER_NAME_IN_OUTER_LAMBDA\")\n    private fun handleQualifiedExpression(node: ASTNode) {\n        (node.psi as KtDotQualifiedExpression).selectorExpression?.node?.let {\n            if (it.findChildByType(REFERENCE_EXPRESSION)?.getIdentifierName()?.text == \"rangeTo\") {\n                val arguments = it.findChildByType(VALUE_ARGUMENT_LIST)?.getChildren(TokenSet.create(VALUE_ARGUMENT))\n                if (arguments?.size == 1) {\n                    CONVENTIONAL_RANGE.warnAndFix(configRules, emitWarn, isFixMode, \"replace `rangeTo` with `..`: ${node.text}\", node.startOffset, node) {\n                        val receiverExpression = (node.psi as KtDotQualifiedExpression).receiverExpression.text\n                        val correctNode = KotlinParser().createNode(\"$receiverExpression..${arguments[0].text}\")\n                        node.treeParent.addChild(correctNode, node)\n                        node.treeParent.removeChild(node)\n                    }\n                }\n            }\n        }\n    }\n\n    @Suppress(\"TOO_MANY_LINES_IN_LAMBDA\")\n    private fun handleRange(node: ASTNode) {\n        val binaryInExpression = node.parent(BINARY_EXPRESSION)?.psi as KtBinaryExpression?\n        binaryInExpression\n            ?.right\n            ?.node\n            // Unwrap parentheses and get `BINARY_EXPRESSION` on the RHS of `..`\n            ?.takeByChainOfTypes(BINARY_EXPRESSION)\n            ?.run { psi as? KtBinaryExpression }\n            ?.takeIf { it.operationReference.node.hasChildOfType(MINUS) }\n            ?.let { upperBoundExpression ->\n                val isMinusOne = (upperBoundExpression.right as? KtConstantExpression)?.firstChild?.let {\n                    it.node.elementType == INTEGER_LITERAL && it.text == \"1\"\n                } ?: false\n                if (!isMinusOne) {\n                    return@let\n                }\n                // At this point we are sure that `upperBoundExpression` is `[left] - 1` and should be replaced.\n                val errorNode = binaryInExpression.node\n                CONVENTIONAL_RANGE.warnAndFix(configRules, emitWarn, isFixMode, \"replace `..` with `until`: ${errorNode.text}\", errorNode.startOffset, errorNode) {\n                    // Replace `..` with `until`\n                    replaceUntil(node)\n                    // fix right side of binary expression to correct form (remove ` - 1 `) : (b-1) -> (b)\n                    val astNode = upperBoundExpression.node\n                    val parent = astNode.treeParent\n                    parent.addChild(astNode.firstChildNode, astNode)\n                    parent.removeChild(astNode)\n                }\n            }\n    }\n\n    private fun replaceUntil(node: ASTNode) {\n        val untilNode = LeafPsiElement(IDENTIFIER, \"until\")\n        val parent = node.treeParent\n        if (parent.treePrev?.isWhiteSpace() != true) {\n            parent.treeParent.addChild(PsiWhiteSpaceImpl(\" \"), parent)\n        }\n        if (parent.treeNext?.isWhiteSpace() != true) {\n            parent.treeParent.addChild(PsiWhiteSpaceImpl(\" \"), parent.treeNext)\n        }\n        parent.addChild(untilNode, node)\n        parent.removeChild(node)\n    }\n\n    /**\n     *\n     * [RuleConfiguration] for rangeTo function\n     */\n    class RangeConventionalConfiguration(config: Map<String, String>) : RuleConfiguration(config) {\n        /**\n         * If true, don't suggest to replace `rangeTo` function with operator `..`\n         */\n        val isRangeToIgnore = config[\"isRangeToIgnore\"]?.toBoolean() ?: false\n    }\n\n    companion object {\n        const val NAME_ID = \"range\"\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/main/kotlin/com/saveourtool/diktat/ruleset/rules/chapter3/SingleLineStatementsRule.kt",
    "content": "package com.saveourtool.diktat.ruleset.rules.chapter3\n\nimport com.saveourtool.diktat.common.config.rules.RulesConfig\nimport com.saveourtool.diktat.ruleset.constants.Warnings.MORE_THAN_ONE_STATEMENT_PER_LINE\nimport com.saveourtool.diktat.ruleset.rules.DiktatRule\nimport com.saveourtool.diktat.ruleset.utils.appendNewlineMergingWhiteSpace\nimport com.saveourtool.diktat.ruleset.utils.extractLineOfText\nimport com.saveourtool.diktat.ruleset.utils.isBeginByNewline\nimport com.saveourtool.diktat.ruleset.utils.isFollowedByNewline\nimport com.saveourtool.diktat.ruleset.utils.parent\n\nimport org.jetbrains.kotlin.KtNodeTypes.ENUM_ENTRY\nimport org.jetbrains.kotlin.com.intellij.lang.ASTNode\nimport org.jetbrains.kotlin.com.intellij.psi.impl.source.tree.PsiWhiteSpaceImpl\nimport org.jetbrains.kotlin.com.intellij.psi.tree.TokenSet\nimport org.jetbrains.kotlin.lexer.KtTokens.SEMICOLON\n\n/**\n * Rule that looks for multiple statements on a single line separated with a `;` and splits them in multiple lines.\n */\nclass SingleLineStatementsRule(configRules: List<RulesConfig>) : DiktatRule(\n    NAME_ID,\n    configRules,\n    listOf(MORE_THAN_ONE_STATEMENT_PER_LINE)\n) {\n    override fun logic(node: ASTNode) {\n        checkSemicolon(node)\n    }\n\n    private fun checkSemicolon(node: ASTNode) {\n        node.getChildren(semicolonToken).forEach { astNode ->\n            if (!astNode.isFollowedByNewline()) {\n                MORE_THAN_ONE_STATEMENT_PER_LINE.warnAndFix(configRules, emitWarn, isFixMode, astNode.extractLineOfText(),\n                    astNode.startOffset, astNode) {\n                    if (astNode.treeParent.elementType == ENUM_ENTRY) {\n                        node.treeParent.addChild(PsiWhiteSpaceImpl(\"\\n\"), node.treeNext)\n                    } else {\n                        if (!astNode.isBeginByNewline()) {\n                            val nextNode = astNode.parent(false) { parent -> parent.treeNext != null }?.treeNext\n                            node.appendNewlineMergingWhiteSpace(nextNode, astNode)\n                        }\n                        node.removeChild(astNode)\n                    }\n                }\n            }\n        }\n    }\n\n    companion object {\n        const val NAME_ID = \"statement\"\n        private val semicolonToken = TokenSet.create(SEMICOLON)\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/main/kotlin/com/saveourtool/diktat/ruleset/rules/chapter3/SortRule.kt",
    "content": "package com.saveourtool.diktat.ruleset.rules.chapter3\n\nimport com.saveourtool.diktat.common.config.rules.RuleConfiguration\nimport com.saveourtool.diktat.common.config.rules.RulesConfig\nimport com.saveourtool.diktat.common.config.rules.getRuleConfig\nimport com.saveourtool.diktat.ruleset.constants.Warnings.WRONG_DECLARATIONS_ORDER\nimport com.saveourtool.diktat.ruleset.rules.DiktatRule\nimport com.saveourtool.diktat.ruleset.utils.findAllDescendantsWithSpecificType\nimport com.saveourtool.diktat.ruleset.utils.hasChildOfType\nimport com.saveourtool.diktat.ruleset.utils.isClassEnum\nimport com.saveourtool.diktat.ruleset.utils.isPartOfComment\nimport com.saveourtool.diktat.ruleset.utils.isWhiteSpace\nimport com.saveourtool.diktat.ruleset.utils.isWhiteSpaceWithNewline\nimport com.saveourtool.diktat.ruleset.utils.nextSibling\n\nimport org.jetbrains.kotlin.KtNodeTypes.CLASS_BODY\nimport org.jetbrains.kotlin.KtNodeTypes.ENUM_ENTRY\nimport org.jetbrains.kotlin.KtNodeTypes.MODIFIER_LIST\nimport org.jetbrains.kotlin.KtNodeTypes.PROPERTY\nimport org.jetbrains.kotlin.com.intellij.lang.ASTNode\nimport org.jetbrains.kotlin.com.intellij.psi.impl.source.tree.LeafPsiElement\nimport org.jetbrains.kotlin.com.intellij.psi.impl.source.tree.PsiWhiteSpaceImpl\nimport org.jetbrains.kotlin.lexer.KtTokens.COMMA\nimport org.jetbrains.kotlin.lexer.KtTokens.CONST_KEYWORD\nimport org.jetbrains.kotlin.lexer.KtTokens.EOL_COMMENT\nimport org.jetbrains.kotlin.lexer.KtTokens.IDENTIFIER\nimport org.jetbrains.kotlin.lexer.KtTokens.SEMICOLON\nimport org.jetbrains.kotlin.psi.KtObjectDeclaration\nimport org.jetbrains.kotlin.psi.psiUtil.siblings\n\n/**\n * Rule that sorts class properties and enum members alphabetically\n */\nclass SortRule(configRules: List<RulesConfig>) : DiktatRule(\n    NAME_ID,\n    configRules,\n    listOf(WRONG_DECLARATIONS_ORDER),\n) {\n    override fun logic(node: ASTNode) {\n        val configuration = SortRuleConfiguration(\n            configRules.getRuleConfig(WRONG_DECLARATIONS_ORDER)?.configuration ?: emptyMap()\n        )\n\n        val classBody = node.findChildByType(CLASS_BODY)\n        if (node.isClassEnum() && classBody != null && configuration.sortEnum) {\n            sortEnum(classBody)\n        }\n        if ((node.psi as? KtObjectDeclaration)?.isCompanion() == true && classBody != null &&\n                configuration.sortProperty) {\n            sortProperty(classBody)\n        }\n    }\n\n    @Suppress(\"UnsafeCallOnNullableType\")\n    private fun sortProperty(node: ASTNode) {\n        val propertyList = node\n            .getChildren(null)\n            .filter { it.elementType == PROPERTY }\n            .filter { it.hasChildOfType(MODIFIER_LIST) }\n            .filter { it.findChildByType(MODIFIER_LIST)!!.hasChildOfType(CONST_KEYWORD) }\n        if (propertyList.size <= 1) {\n            return\n        }\n        val consecutivePropertiesGroups = createOrderListOfList(propertyList)\n        val sortedListOfList = consecutivePropertiesGroups.map { group ->\n            group.sortedBy { it.findChildByType(IDENTIFIER)!!.text }\n        }\n        consecutivePropertiesGroups.forEachIndexed { index, mutableList ->\n            if (mutableList != sortedListOfList[index]) {\n                WRONG_DECLARATIONS_ORDER.warnAndFix(configRules, emitWarn, isFixMode,\n                    \"constant properties inside companion object order is incorrect\",\n                    mutableList.first().startOffset, mutableList.first()) {\n                    swapSortNodes(sortedListOfList[index], mutableList, node)\n                }\n            }\n        }\n    }\n\n    @OptIn(ExperimentalStdlibApi::class)\n    private fun swapSortNodes(\n        sortList: List<ASTNode>,\n        nonSortList: List<ASTNode>,\n        node: ASTNode\n    ) {\n        val isEnum = nonSortList.first().elementType == ENUM_ENTRY\n        val spaceBefore = if (node.findAllDescendantsWithSpecificType(EOL_COMMENT).isNotEmpty() && isEnum) {\n            nonSortList.last().run {\n                if (this.hasChildOfType(EOL_COMMENT) && !this.hasChildOfType(COMMA)) {\n                    this.addChild(LeafPsiElement(COMMA, \",\"), this.findChildByType(EOL_COMMENT))\n                }\n            }\n            buildList(nonSortList.size) {\n                add(null)\n                repeat(nonSortList.size - 1) {\n                    add(listOf(PsiWhiteSpaceImpl(\"\\n\")))\n                }\n            }\n        } else {\n            nonSortList.map { astNode ->\n                astNode\n                    .siblings(false)\n                    .toList()\n                    .takeWhile { it.isWhiteSpace() || it.isPartOfComment() }\n                    .ifEmpty { null }\n            }\n        }\n        val nodeInsertBefore: ASTNode? = nonSortList.last().treeNext\n        node.removeRange(nonSortList.first(), nonSortList.last().treeNext)\n        sortList.mapIndexed { index, astNode ->\n            spaceBefore[index]?.let { prevList -> prevList.map { node.addChild(it, nodeInsertBefore) } }\n            if (!astNode.hasChildOfType(COMMA) && isEnum) {\n                astNode.addChild(LeafPsiElement(COMMA, \",\"), null)\n            }\n            node.addChild(astNode, nodeInsertBefore)\n        }\n    }\n\n    @Suppress(\"TYPE_ALIAS\")\n    private fun createOrderListOfList(propertyList: List<ASTNode>): List<List<ASTNode>> {\n        val oneOrderList = mutableListOf(propertyList.first())\n        val orderListOfList: MutableList<MutableList<ASTNode>> = mutableListOf()\n        propertyList.zipWithNext().forEach { (currentProperty, nextProperty) ->\n            if (currentProperty.nextSibling { it.elementType == PROPERTY } != nextProperty) {\n                orderListOfList.add(oneOrderList.toMutableList())\n                oneOrderList.clear()\n            }\n            oneOrderList.add(nextProperty)\n        }\n        orderListOfList.add(oneOrderList)\n        return orderListOfList.toList()\n    }\n\n    @Suppress(\"UnsafeCallOnNullableType\")\n    private fun sortEnum(node: ASTNode) {\n        val enumEntryList = node.getChildren(null).filter { it.elementType == ENUM_ENTRY }\n        if (enumEntryList.size <= 1) {\n            return\n        }\n        val sortList = enumEntryList.sortedBy { it.findChildByType(IDENTIFIER)!!.text }\n        if (enumEntryList != sortList) {\n            WRONG_DECLARATIONS_ORDER.warnAndFix(configRules, emitWarn, isFixMode, \"enum entries order is incorrect\", node.startOffset, node) {\n                val (isEndSemicolon, isEndSpace) = removeLastSemicolonAndSpace(enumEntryList.last())\n                val hasTrailingComma = (sortList.last() != enumEntryList.last() && enumEntryList.last().hasChildOfType(COMMA))\n                swapSortNodes(sortList, enumEntryList, node)\n                if (!hasTrailingComma) {\n                    val lastEntry = node.findAllDescendantsWithSpecificType(ENUM_ENTRY).last()\n                    lastEntry.removeChild(lastEntry.findChildByType(COMMA)!!)\n                }\n                if (isEndSpace) {\n                    sortList.last().addChild(PsiWhiteSpaceImpl(\"\\n\"), null)\n                }\n                if (isEndSemicolon) {\n                    sortList.last().addChild(LeafPsiElement(SEMICOLON, \";\"), null)\n                }\n            }\n        }\n    }\n\n    @Suppress(\"UnsafeCallOnNullableType\")\n    private fun removeLastSemicolonAndSpace(node: ASTNode): Pair<Boolean, Boolean> {\n        val isSemicolon = node.hasChildOfType(SEMICOLON)\n        if (isSemicolon) {\n            node.removeChild(node.findChildByType(SEMICOLON)!!)\n        }\n        val isSpace = node.lastChildNode.isWhiteSpaceWithNewline()\n        if (isSpace) {\n            node.removeChild(node.lastChildNode)\n        }\n        return Pair(isSemicolon, isSpace)\n    }\n\n    /**\n     * [RuleConfiguration] for rule that sorts class members\n     */\n    class SortRuleConfiguration(config: Map<String, String>) : RuleConfiguration(config) {\n        /**\n         * Whether enum members should be sorted alphabetically\n         */\n        val sortEnum = config[\"sortEnum\"]?.toBoolean() ?: false\n\n        /**\n         * Whether class properties should be sorted alphabetically\n         */\n        val sortProperty = config[\"sortProperty\"]?.toBoolean() ?: false\n    }\n\n    companion object {\n        const val NAME_ID = \"sort-rule\"\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/main/kotlin/com/saveourtool/diktat/ruleset/rules/chapter3/StringConcatenationRule.kt",
    "content": "package com.saveourtool.diktat.ruleset.rules.chapter3\n\nimport com.saveourtool.diktat.common.config.rules.RulesConfig\nimport com.saveourtool.diktat.ruleset.constants.Warnings.STRING_CONCATENATION\nimport com.saveourtool.diktat.ruleset.rules.DiktatRule\nimport com.saveourtool.diktat.ruleset.utils.*\n\nimport org.jetbrains.kotlin.KtNodeTypes.BINARY_EXPRESSION\nimport org.jetbrains.kotlin.KtNodeTypes.DOT_QUALIFIED_EXPRESSION\nimport org.jetbrains.kotlin.KtNodeTypes.OPERATION_REFERENCE\nimport org.jetbrains.kotlin.KtNodeTypes.STRING_TEMPLATE\nimport org.jetbrains.kotlin.com.intellij.lang.ASTNode\nimport org.jetbrains.kotlin.lexer.KtTokens.PLUS\nimport org.jetbrains.kotlin.psi.KtBinaryExpression\nimport org.jetbrains.kotlin.psi.KtCallExpression\nimport org.jetbrains.kotlin.psi.KtConstantExpression\nimport org.jetbrains.kotlin.psi.KtDotQualifiedExpression\nimport org.jetbrains.kotlin.psi.KtExpression\nimport org.jetbrains.kotlin.psi.KtParenthesizedExpression\nimport org.jetbrains.kotlin.psi.KtReferenceExpression\nimport org.jetbrains.kotlin.psi.KtStringTemplateExpression\n\n/**\n * This rule covers checks and fixes related to string concatenation.\n * Rule 3.8 prohibits string concatenation and suggests to use string templates instead\n * if this expressions fits one line. For example:\n * \"\"\" string \"\"\" + \"string\" will be converted to \"string string\"\n * \"string \" + 1 will be converted to \"string 1\"\n * \"string one \" + \"string two \"\n */\nclass StringConcatenationRule(configRules: List<RulesConfig>) : DiktatRule(\n    NAME_ID,\n    configRules,\n    listOf(\n        STRING_CONCATENATION\n    )\n) {\n    @Suppress(\"COLLAPSE_IF_STATEMENTS\")\n    override fun logic(node: ASTNode) {\n        if (node.elementType == BINARY_EXPRESSION) {\n            // searching top-level binary expression to detect any operations with \"plus\" (+)\n            // string concatenation is prohibited only for single line statements\n            if (node.findParentNodeWithSpecificType(BINARY_EXPRESSION) == null && isSingleLineStatement(node)) {\n                detectStringConcatenation(node)\n            }\n        }\n    }\n\n    private fun isSingleLineStatement(node: ASTNode): Boolean =\n        !node.text.contains(\"\\n\")\n\n    /**\n     * This method works only with top-level binary expressions. It should be checked before the call.\n     */\n    @Suppress(\"AVOID_NULL_CHECKS\")\n    private fun detectStringConcatenation(topLevelBinaryExpr: ASTNode) {\n        val allBinaryExpressions = topLevelBinaryExpr.findAllDescendantsWithSpecificType(BINARY_EXPRESSION)\n        val nodeWithBug = allBinaryExpressions.find { isDetectStringConcatenationInExpression(it) }\n\n        if (nodeWithBug != null) {\n            STRING_CONCATENATION.warnAndFix(\n                configRules, emitWarn,\n                this.isFixMode, topLevelBinaryExpr.text.lines().first(), nodeWithBug.startOffset, nodeWithBug\n            ) {\n                fixBinaryExpressionWithConcatenation(nodeWithBug)\n                loop(topLevelBinaryExpr.treeParent)\n            }\n        }\n    }\n\n    private fun loop(parentTopLevelBinaryExpr: ASTNode) {\n        val allBinaryExpressions = parentTopLevelBinaryExpr.findAllDescendantsWithSpecificType(BINARY_EXPRESSION)\n        val nodeWithBug = allBinaryExpressions.find { isDetectStringConcatenationInExpression(it) }\n\n        val bugDetected = nodeWithBug != null\n        if (bugDetected) {\n            fixBinaryExpressionWithConcatenation(nodeWithBug)\n            loop(parentTopLevelBinaryExpr)\n        }\n    }\n\n    /**\n     * We can detect string concatenation by the first (left) operand in binary expression.\n     * If it is of type string - then we found string concatenation.\n     * If the right value is not a constant string then don't change them to template.\n     */\n    private fun isDetectStringConcatenationInExpression(node: ASTNode): Boolean {\n        require(node.elementType == BINARY_EXPRESSION) {\n            \"cannot process non binary expression in the process of detecting string concatenation\"\n        }\n        val firstChild = node.firstChildNode\n        val lastChild = node.lastChildNode\n        return isPlusBinaryExpression(node) && isStringVar(firstChild, lastChild)\n    }\n\n    private fun isStringVar(firstChild: ASTNode, lastChild: ASTNode) = firstChild.elementType == STRING_TEMPLATE ||\n            ((firstChild.text.endsWith(\"toString()\")) && firstChild.elementType == DOT_QUALIFIED_EXPRESSION && lastChild.elementType == STRING_TEMPLATE)\n\n    @Suppress(\"COMMENT_WHITE_SPACE\")\n    private fun isPlusBinaryExpression(node: ASTNode): Boolean {\n        require(node.elementType == BINARY_EXPRESSION)\n        //     binary expression\n        //    /        |        \\\n        //  expr1 operationRef expr2\n\n        val operationReference = node.getFirstChildWithType(OPERATION_REFERENCE)\n        return operationReference\n            ?.getFirstChildWithType(PLUS) != null\n    }\n\n    private fun fixBinaryExpressionWithConcatenation(node: ASTNode?) {\n        val binaryExpressionPsi = node?.psi as KtBinaryExpression\n        val parentNode = node.treeParent\n        val textNode = checkKtExpression(binaryExpressionPsi)\n        val newNode = KotlinParser().createNode(\"\\\"$textNode\\\"\")\n        parentNode.replaceChild(node, newNode)\n    }\n\n    private fun isPlusBinaryExpressionAndFirstElementString(binaryExpressionNode: KtBinaryExpression) =\n        (binaryExpressionNode.left is KtStringTemplateExpression) && PLUS == binaryExpressionNode.operationToken\n\n    @Suppress(\n        \"TOO_LONG_FUNCTION\",\n        \"NESTED_BLOCK\",\n        \"SAY_NO_TO_VAR\",\n        \"ComplexMethod\"\n    )\n    private fun checkKtExpression(binaryExpressionPsi: KtBinaryExpression): String {\n        var lvalueText = binaryExpressionPsi.left?.text?.trim('\"')\n        val rvalueText = binaryExpressionPsi.right?.text\n\n        if (binaryExpressionPsi.isLvalueDotQualifiedExpression() && binaryExpressionPsi.firstChild.text.endsWith(\"toString()\")) {\n            // =========== (1 + 2).toString() -> ${(1 + 2)}\n            val leftText = binaryExpressionPsi.firstChild.firstChild.text\n            lvalueText = \"\\${$leftText}\"\n        }\n        if (binaryExpressionPsi.isLvalueReferenceExpression() || binaryExpressionPsi.isLvalueConstantExpression()) {\n            return binaryExpressionPsi.text\n        }\n        if (binaryExpressionPsi.isLvalueBinaryExpression()) {\n            val rightValue = checkKtExpression(binaryExpressionPsi.left as KtBinaryExpression)\n            val rightEx = binaryExpressionPsi.right\n            val rightVal = if (binaryExpressionPsi.isRvalueParenthesized()) {\n                checkKtExpression(rightEx?.children?.get(0) as KtBinaryExpression)\n            } else {\n                (rightEx?.text?.trim('\"'))\n            }\n            if (binaryExpressionPsi.left?.text == rightValue) {\n                return binaryExpressionPsi.text\n            }\n            return \"$rightValue$rightVal\"\n        } else if (binaryExpressionPsi.isRvalueConstantExpression() || binaryExpressionPsi.isRvalueStringTemplateExpression()) {\n            // =========== \"a \" + \"b\" -> \"a b\"\n            val rvalueTextNew = rvalueText?.trim('\"')\n            return \"$lvalueText$rvalueTextNew\"\n        } else if (binaryExpressionPsi.isRvalueCallExpression()) {\n            // ===========  \"a \" + foo() -> \"a ${foo()}}\"\n            return \"$lvalueText\\${$rvalueText}\"\n        } else if (binaryExpressionPsi.isRvalueReferenceExpression()) {\n            // ===========  \"a \" + b -> \"a $b\"\n            return \"$lvalueText$$rvalueText\"\n        } else if (!binaryExpressionPsi.isRvalueParenthesized() && binaryExpressionPsi.isRvalueExpression()) {\n            return \"$lvalueText\\${$rvalueText}\"\n        } else if (binaryExpressionPsi.isRvalueParenthesized()) {\n            val binExpression = binaryExpressionPsi.right?.children?.first()\n            if (binExpression is KtBinaryExpression) {\n                if (isPlusBinaryExpressionAndFirstElementString(binExpression)) {\n                    val rightValue = checkKtExpression(binExpression)\n                    return \"$lvalueText$rightValue\"\n                } else if (binExpression.isLvalueBinaryExpression()) {\n                    val rightValue = checkKtExpression(binExpression.left as KtBinaryExpression)\n                    val rightEx = binExpression.right\n                    val rightVal = if (binExpression.isRvalueParenthesized()) {\n                        checkKtExpression(rightEx?.children?.get(0) as KtBinaryExpression)\n                    } else {\n                        (rightEx?.text?.trim('\"'))\n                    }\n                    if (binExpression.left?.text == rightValue) {\n                        return \"$lvalueText\\${$rvalueText}\"\n                    }\n                    return \"$lvalueText$rightValue$rightVal\"\n                }\n            }\n            return \"$lvalueText\\${$rvalueText}\"\n        }\n        return binaryExpressionPsi.text\n    }\n\n    private fun KtBinaryExpression.isRvalueConstantExpression() =\n        this.right is KtConstantExpression\n\n    private fun KtBinaryExpression.isRvalueStringTemplateExpression() =\n        this.right is KtStringTemplateExpression\n\n    private fun KtBinaryExpression.isRvalueCallExpression() =\n        this.right is KtCallExpression\n\n    private fun KtBinaryExpression.isRvalueReferenceExpression() =\n        this.right is KtReferenceExpression\n\n    private fun KtBinaryExpression.isRvalueParenthesized() =\n        this.right is KtParenthesizedExpression\n\n    private fun KtBinaryExpression.isLvalueDotQualifiedExpression() =\n        this.left is KtDotQualifiedExpression\n\n    private fun KtBinaryExpression.isLvalueBinaryExpression() =\n        this.left is KtBinaryExpression\n\n    private fun KtBinaryExpression.isLvalueReferenceExpression() =\n        this.left is KtReferenceExpression\n\n    private fun KtBinaryExpression.isLvalueConstantExpression() =\n        this.left is KtConstantExpression\n\n    private fun KtBinaryExpression.isRvalueExpression() =\n        this.right is KtExpression\n\n    companion object {\n        const val NAME_ID = \"string-concatenation\"\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/main/kotlin/com/saveourtool/diktat/ruleset/rules/chapter3/StringTemplateFormatRule.kt",
    "content": "package com.saveourtool.diktat.ruleset.rules.chapter3\n\nimport com.saveourtool.diktat.common.config.rules.RulesConfig\nimport com.saveourtool.diktat.ruleset.constants.Warnings.STRING_TEMPLATE_CURLY_BRACES\nimport com.saveourtool.diktat.ruleset.constants.Warnings.STRING_TEMPLATE_QUOTES\nimport com.saveourtool.diktat.ruleset.rules.DiktatRule\nimport com.saveourtool.diktat.ruleset.utils.findAllDescendantsWithSpecificType\nimport com.saveourtool.diktat.ruleset.utils.hasAnyChildOfTypes\n\nimport org.jetbrains.kotlin.KtNodeTypes.ARRAY_ACCESS_EXPRESSION\nimport org.jetbrains.kotlin.KtNodeTypes.FLOAT_CONSTANT\nimport org.jetbrains.kotlin.KtNodeTypes.INTEGER_CONSTANT\nimport org.jetbrains.kotlin.KtNodeTypes.LITERAL_STRING_TEMPLATE_ENTRY\nimport org.jetbrains.kotlin.KtNodeTypes.LONG_STRING_TEMPLATE_ENTRY\nimport org.jetbrains.kotlin.KtNodeTypes.REFERENCE_EXPRESSION\nimport org.jetbrains.kotlin.KtNodeTypes.SHORT_STRING_TEMPLATE_ENTRY\nimport org.jetbrains.kotlin.com.intellij.lang.ASTNode\nimport org.jetbrains.kotlin.com.intellij.psi.impl.source.tree.CompositeElement\nimport org.jetbrains.kotlin.com.intellij.psi.impl.source.tree.LeafPsiElement\nimport org.jetbrains.kotlin.lexer.KtTokens.CLOSING_QUOTE\nimport org.jetbrains.kotlin.lexer.KtTokens.IDENTIFIER\nimport org.jetbrains.kotlin.lexer.KtTokens.SHORT_TEMPLATE_ENTRY_START\n\n/**\n * In String templates there should not be redundant curly braces. In case of using a not complex statement (one argument)\n * there should not be curly braces.\n *\n * FixMe: The important caveat here: in \"$foo\" kotlin compiler adds implicit call to foo.toString() in case foo type is not string.\n */\nclass StringTemplateFormatRule(configRules: List<RulesConfig>) : DiktatRule(\n    NAME_ID,\n    configRules,\n    listOf(STRING_TEMPLATE_CURLY_BRACES, STRING_TEMPLATE_QUOTES)\n) {\n    override fun logic(node: ASTNode) {\n        when (node.elementType) {\n            LONG_STRING_TEMPLATE_ENTRY -> handleLongStringTemplate(node)\n            SHORT_STRING_TEMPLATE_ENTRY -> handleShortStringTemplate(node)\n            else -> {\n            }\n        }\n    }\n\n    @Suppress(\"UnsafeCallOnNullableType\")\n    private fun handleLongStringTemplate(node: ASTNode) {\n        // Checking if in long templates {a.foo()} there are function calls or class toString call\n        if (bracesCanBeOmitted(node)) {\n            STRING_TEMPLATE_CURLY_BRACES.warnAndFix(configRules, emitWarn, isFixMode, node.text, node.startOffset, node) {\n                val identifierName = node.findChildByType(REFERENCE_EXPRESSION)\n                identifierName?.let {\n                    val shortTemplate = CompositeElement(SHORT_STRING_TEMPLATE_ENTRY)\n                    val reference = CompositeElement(REFERENCE_EXPRESSION)\n\n                    node.treeParent.addChild(shortTemplate, node)\n                    shortTemplate.addChild(LeafPsiElement(SHORT_TEMPLATE_ENTRY_START, \"$\"), null)\n                    shortTemplate.addChild(reference)\n                    reference.addChild(LeafPsiElement(IDENTIFIER, identifierName.text))\n                    node.treeParent.removeChild(node)\n                }\n                    ?: run {\n                        val stringTemplate = node.treeParent\n                        val appropriateText = node.text.trim('$', '{', '}')\n                        stringTemplate.addChild(LeafPsiElement(LITERAL_STRING_TEMPLATE_ENTRY, appropriateText), node)\n                        stringTemplate.removeChild(node)\n                    }\n            }\n        }\n    }\n\n    @Suppress(\"UnsafeCallOnNullableType\")\n    private fun handleShortStringTemplate(node: ASTNode) {\n        val identifierName = node.findChildByType(REFERENCE_EXPRESSION)?.text\n\n        if (identifierName != null && node.treeParent.text.trim('\"', '$') == identifierName) {\n            STRING_TEMPLATE_QUOTES.warnAndFix(configRules, emitWarn, isFixMode, node.text, node.startOffset, node) {\n                val identifier = node.findChildByType(REFERENCE_EXPRESSION)!!\n                // node.treeParent is String template that we need to delete\n                node.treeParent.treeParent.addChild(identifier, node.treeParent)\n                node.treeParent.treeParent.removeChild(node.treeParent)\n            }\n        }\n    }\n\n    @Suppress(\"UnsafeCallOnNullableType\", \"FUNCTION_BOOLEAN_PREFIX\")\n    private fun bracesCanBeOmitted(node: ASTNode): Boolean {\n        val onlyOneRefExpr = node\n            .findAllDescendantsWithSpecificType(REFERENCE_EXPRESSION)\n            .singleOrNull()\n            ?.treeParent\n            ?.elementType == LONG_STRING_TEMPLATE_ENTRY\n\n        val isArrayAccessExpression = node  // this should be omitted in previous expression, used for safe warranties\n            .findAllDescendantsWithSpecificType(REFERENCE_EXPRESSION)\n            .singleOrNull()\n            ?.treeParent\n            ?.elementType == ARRAY_ACCESS_EXPRESSION\n\n        return if (onlyOneRefExpr && !isArrayAccessExpression) {\n            (!(node.treeNext\n                .text\n                .first()\n                // checking if first letter is valid\n                .isLetterOrDigit() ||\n                    node.treeNext.text.startsWith(\"_\")) ||\n                    node.treeNext.elementType == CLOSING_QUOTE\n            )\n        } else if (!isArrayAccessExpression) {\n            node.hasAnyChildOfTypes(FLOAT_CONSTANT, INTEGER_CONSTANT)  // it also fixes \"${1.0}asd\" cases\n        } else {\n            false\n        }\n    }\n\n    companion object {\n        const val NAME_ID = \"string-template-format\"\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/main/kotlin/com/saveourtool/diktat/ruleset/rules/chapter3/TrailingCommaRule.kt",
    "content": "package com.saveourtool.diktat.ruleset.rules.chapter3\n\nimport com.saveourtool.diktat.common.config.rules.RuleConfiguration\nimport com.saveourtool.diktat.common.config.rules.RulesConfig\nimport com.saveourtool.diktat.common.config.rules.getCommonConfiguration\nimport com.saveourtool.diktat.common.config.rules.getRuleConfig\nimport com.saveourtool.diktat.ruleset.constants.Warnings.TRAILING_COMMA\nimport com.saveourtool.diktat.ruleset.rules.DiktatRule\nimport com.saveourtool.diktat.ruleset.utils.isPartOfComment\nimport com.saveourtool.diktat.ruleset.utils.isWhiteSpaceWithNewline\n\nimport io.github.oshai.kotlinlogging.KotlinLogging\nimport org.jetbrains.kotlin.KtNodeTypes.COLLECTION_LITERAL_EXPRESSION\nimport org.jetbrains.kotlin.KtNodeTypes.DESTRUCTURING_DECLARATION\nimport org.jetbrains.kotlin.KtNodeTypes.DESTRUCTURING_DECLARATION_ENTRY\nimport org.jetbrains.kotlin.KtNodeTypes.INDICES\nimport org.jetbrains.kotlin.KtNodeTypes.REFERENCE_EXPRESSION\nimport org.jetbrains.kotlin.KtNodeTypes.STRING_TEMPLATE\nimport org.jetbrains.kotlin.KtNodeTypes.TYPE_ARGUMENT_LIST\nimport org.jetbrains.kotlin.KtNodeTypes.TYPE_PARAMETER\nimport org.jetbrains.kotlin.KtNodeTypes.TYPE_PARAMETER_LIST\nimport org.jetbrains.kotlin.KtNodeTypes.TYPE_PROJECTION\nimport org.jetbrains.kotlin.KtNodeTypes.VALUE_ARGUMENT\nimport org.jetbrains.kotlin.KtNodeTypes.VALUE_ARGUMENT_LIST\nimport org.jetbrains.kotlin.KtNodeTypes.VALUE_PARAMETER\nimport org.jetbrains.kotlin.KtNodeTypes.VALUE_PARAMETER_LIST\nimport org.jetbrains.kotlin.KtNodeTypes.WHEN_CONDITION_EXPRESSION\nimport org.jetbrains.kotlin.KtNodeTypes.WHEN_CONDITION_IN_RANGE\nimport org.jetbrains.kotlin.KtNodeTypes.WHEN_CONDITION_IS_PATTERN\nimport org.jetbrains.kotlin.KtNodeTypes.WHEN_ENTRY\nimport org.jetbrains.kotlin.com.intellij.lang.ASTFactory\nimport org.jetbrains.kotlin.com.intellij.lang.ASTNode\nimport org.jetbrains.kotlin.kdoc.lexer.KDocTokens.KDOC\nimport org.jetbrains.kotlin.lexer.KtTokens.BLOCK_COMMENT\nimport org.jetbrains.kotlin.lexer.KtTokens.COMMA\nimport org.jetbrains.kotlin.lexer.KtTokens.EOL_COMMENT\nimport org.jetbrains.kotlin.psi.psiUtil.children\nimport org.jetbrains.kotlin.psi.psiUtil.siblings\n\n/**\n * [1] Enumerations (In another rule)\n * [2] Value arguments\n * [3] Class properties and parameters\n * [4] Function value parameters\n * [5] Parameters with optional type (including setters)\n * [6] Indexing suffix\n * [7] Lambda parameters\n * [8] when entry\n * [9] Collection literals (in annotations)Type arguments\n * [10] Type arguments\n * [11] Type parameters\n * [12] Destructuring declarations\n */\n@Suppress(\"TOO_LONG_FUNCTION\")\nclass TrailingCommaRule(configRules: List<RulesConfig>) : DiktatRule(\n    NAME_ID,\n    configRules,\n    listOf(TRAILING_COMMA)\n) {\n    private val commonConfig = configRules.getCommonConfiguration()\n    private val trailingConfig = this.configRules.getRuleConfig(TRAILING_COMMA)?.configuration ?: emptyMap()\n    private val configuration by lazy {\n        if (trailingConfig.isEmpty()) {\n            log.warn {\n                \"You have enabled TRAILING_COMMA, but rule will remain inactive until you explicitly set\" +\n                        \" configuration options. See [available-rules.md] for possible configuration options.\"\n            }\n        }\n        TrailingCommaConfiguration(trailingConfig)\n    }\n\n    override fun logic(node: ASTNode) {\n        if (commonConfig.kotlinVersion >= ktVersion) {\n            val (type, config) = when (node.elementType) {\n                VALUE_ARGUMENT_LIST -> Pair(VALUE_ARGUMENT, configuration.getParam(\"valueArgument\"))\n                VALUE_PARAMETER_LIST -> Pair(VALUE_PARAMETER, configuration.getParam(\"valueParameter\"))\n                INDICES -> Pair(REFERENCE_EXPRESSION, configuration.getParam(\"referenceExpression\"))\n                WHEN_ENTRY -> {\n                    val lastChildType = node\n                        .children()\n                        .toList()\n                        .findLast { it.elementType in whenChildrenTypes }\n                        ?.elementType\n                    Pair(lastChildType, configuration.getParam(\"whenConditions\"))\n                }\n                COLLECTION_LITERAL_EXPRESSION -> Pair(STRING_TEMPLATE, configuration.getParam(\"collectionLiteral\"))\n                TYPE_ARGUMENT_LIST -> Pair(TYPE_PROJECTION, configuration.getParam(\"typeArgument\"))\n                TYPE_PARAMETER_LIST -> Pair(TYPE_PARAMETER, configuration.getParam(\"typeParameter\"))\n                DESTRUCTURING_DECLARATION -> Pair(\n                    DESTRUCTURING_DECLARATION_ENTRY,\n                    configuration.getParam(\"destructuringDeclaration\")\n                )\n                else -> return\n            }\n            val astNode = node\n                .children()\n                .toList()\n                .lastOrNull { it.elementType == type }\n            astNode?.checkTrailingComma(config)\n        }\n    }\n\n    private fun ASTNode.checkTrailingComma(config: Boolean) {\n        val noCommaInSiblings = siblings(true).toSet()\n            .let { siblings ->\n                siblings.none { it.elementType == COMMA } && siblings.any { it.isWhiteSpaceWithNewline() || it.isPartOfComment() }\n            }\n        val noCommaInChildren = children().none { it.elementType == COMMA }\n        val shouldFix = noCommaInSiblings && noCommaInChildren\n\n        if (shouldFix && config) {\n            // we should write type of node in warning, to make it easier for user to find the parameter\n            TRAILING_COMMA.warnAndFix(configRules, emitWarn, isFixMode, \"after ${this.elementType}: ${this.text}\", this.startOffset, this) {\n                val parent = this.treeParent\n\n                // In case, when we got VALUE_PARAMETER, it may contain comments, which follows the actual parameter and all of them are actually in the same node\n                // Ex: `class A(val a: Int, val b: Int  // comment)`\n                // `val b: Int  // comment` --> the whole expression is VALUE_PARAMETER\n                // So, in this case we must insert comma before the comment, in other cases we will insert it after current node\n                val comments = listOf(EOL_COMMENT, BLOCK_COMMENT, KDOC)\n                val firstCommentNodeOrNull = if (this.elementType == VALUE_PARAMETER) this.children().firstOrNull { it.elementType in comments } else null\n                firstCommentNodeOrNull?.let {\n                    this.addChild(ASTFactory.leaf(COMMA, \",\"), it)\n                }\n                    ?: parent.addChild(ASTFactory.leaf(COMMA, \",\"), this.treeNext)\n            }\n        }\n    }\n\n    /**\n     * Configuration for trailing comma\n     */\n    class TrailingCommaConfiguration(config: Map<String, String>) : RuleConfiguration(config) {\n        /**\n         * @param name parameters name\n         * @return param based on its name\n         */\n        fun getParam(name: String) = config[name]?.toBoolean() ?: false\n    }\n\n    companion object {\n        private val log = KotlinLogging.logger {}\n        const val NAME_ID = \"trailing-comma\"\n        val ktVersion = KotlinVersion(1, 4)\n        val whenChildrenTypes = listOf(WHEN_CONDITION_EXPRESSION, WHEN_CONDITION_IS_PATTERN, WHEN_CONDITION_IN_RANGE)\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/main/kotlin/com/saveourtool/diktat/ruleset/rules/chapter3/WhenMustHaveElseRule.kt",
    "content": "package com.saveourtool.diktat.ruleset.rules.chapter3\n\nimport com.saveourtool.diktat.common.config.rules.RulesConfig\nimport com.saveourtool.diktat.ruleset.constants.Warnings.WHEN_WITHOUT_ELSE\nimport com.saveourtool.diktat.ruleset.rules.DiktatRule\nimport com.saveourtool.diktat.ruleset.utils.appendNewlineMergingWhiteSpace\nimport com.saveourtool.diktat.ruleset.utils.getAllChildrenWithType\nimport com.saveourtool.diktat.ruleset.utils.getFirstChildWithType\nimport com.saveourtool.diktat.ruleset.utils.hasChildOfType\nimport com.saveourtool.diktat.ruleset.utils.hasParent\nimport com.saveourtool.diktat.ruleset.utils.isBeginByNewline\nimport com.saveourtool.diktat.ruleset.utils.prevSibling\n\nimport org.jetbrains.kotlin.KtNodeTypes\nimport org.jetbrains.kotlin.KtNodeTypes.BINARY_EXPRESSION\nimport org.jetbrains.kotlin.KtNodeTypes.BLOCK\nimport org.jetbrains.kotlin.KtNodeTypes.DOT_QUALIFIED_EXPRESSION\nimport org.jetbrains.kotlin.KtNodeTypes.FUNCTION_LITERAL\nimport org.jetbrains.kotlin.KtNodeTypes.OPERATION_REFERENCE\nimport org.jetbrains.kotlin.KtNodeTypes.PROPERTY\nimport org.jetbrains.kotlin.KtNodeTypes.REFERENCE_EXPRESSION\nimport org.jetbrains.kotlin.KtNodeTypes.RETURN\nimport org.jetbrains.kotlin.KtNodeTypes.WHEN_CONDITION_EXPRESSION\nimport org.jetbrains.kotlin.KtNodeTypes.WHEN_CONDITION_IN_RANGE\nimport org.jetbrains.kotlin.KtNodeTypes.WHEN_CONDITION_IS_PATTERN\nimport org.jetbrains.kotlin.KtNodeTypes.WHEN_ENTRY\nimport org.jetbrains.kotlin.com.intellij.lang.ASTNode\nimport org.jetbrains.kotlin.com.intellij.psi.impl.source.tree.CompositeElement\nimport org.jetbrains.kotlin.com.intellij.psi.impl.source.tree.LeafPsiElement\nimport org.jetbrains.kotlin.com.intellij.psi.impl.source.tree.PsiWhiteSpaceImpl\nimport org.jetbrains.kotlin.com.intellij.psi.impl.source.tree.java.PsiBlockStatementImpl\nimport org.jetbrains.kotlin.lexer.KtTokens.ARROW\nimport org.jetbrains.kotlin.lexer.KtTokens.ELSE_KEYWORD\nimport org.jetbrains.kotlin.lexer.KtTokens.EOL_COMMENT\nimport org.jetbrains.kotlin.lexer.KtTokens.EQ\nimport org.jetbrains.kotlin.lexer.KtTokens.LBRACE\nimport org.jetbrains.kotlin.lexer.KtTokens.RBRACE\nimport org.jetbrains.kotlin.psi.KtWhenExpression\n\n/**\n * Rule 3.10: 'when' statement must have else branch, unless when condition variable is enumerated or sealed type\n *\n * Current limitations and FixMe:\n * If a when statement of type enum or sealed contains all values of a enum - there is no need to have \"else\" branch.\n * The compiler can issue a warning when it is missing.\n */\n@Suppress(\"ForbiddenComment\")\nclass WhenMustHaveElseRule(configRules: List<RulesConfig>) : DiktatRule(\n    NAME_ID,\n    configRules,\n    listOf(WHEN_WITHOUT_ELSE)\n) {\n    override fun logic(node: ASTNode) {\n        if (node.elementType == KtNodeTypes.WHEN && isStatement(node)) {\n            checkEntries(node)\n        }\n    }\n\n    private fun checkEntries(node: ASTNode) {\n        if (!hasElse(node) && !isOnlyEnumEntries(node)) {\n            WHEN_WITHOUT_ELSE.warnAndFix(configRules, emitWarn, isFixMode, \"else was not found\", node.startOffset, node) {\n                val whenEntryElse = CompositeElement(WHEN_ENTRY)\n                if (!node.lastChildNode.isBeginByNewline()) {\n                    node.appendNewlineMergingWhiteSpace(node.lastChildNode.treePrev, node.lastChildNode)\n                }\n                node.addChild(whenEntryElse, node.lastChildNode)\n                addChildren(whenEntryElse)\n                if (!whenEntryElse.isBeginByNewline()) {\n                    node.addChild(PsiWhiteSpaceImpl(\"\\n\"), whenEntryElse)\n                }\n            }\n        }\n    }\n\n    private fun isOnlyEnumEntries(node: ASTNode): Boolean {\n        val whenEntries = node.getAllChildrenWithType(WHEN_ENTRY)\n        val hasConditionsIsPattern = whenEntries.any { it.hasChildOfType(WHEN_CONDITION_IS_PATTERN) }\n        if (hasConditionsIsPattern) {\n            return false\n        }\n\n        val conditionsInRange = whenEntries.map {\n            it.getAllChildrenWithType(WHEN_CONDITION_IN_RANGE)\n        }.flatten()\n\n        val conditionsWithExpression = whenEntries.map {\n            it.getAllChildrenWithType(WHEN_CONDITION_EXPRESSION)\n        }.flatten()\n\n        val areOnlyEnumEntriesWithExpressions = if (conditionsWithExpression.isNotEmpty()) {\n            conditionsWithExpression.all {\n                it.hasChildOfType(DOT_QUALIFIED_EXPRESSION) || it.hasChildOfType(REFERENCE_EXPRESSION)\n            }\n        } else {\n            true\n        }\n\n        val areOnlyEnumEntriesInRanges = if (conditionsInRange.isNotEmpty()) {\n            conditionsInRange.map { it.getFirstChildWithType(BINARY_EXPRESSION) }\n                .all {\n                    val dotExpressionsCount = it?.getAllChildrenWithType(DOT_QUALIFIED_EXPRESSION)?.size ?: 0\n                    val referenceExpressionsCount = it?.getAllChildrenWithType(REFERENCE_EXPRESSION)?.size ?: 0\n                    dotExpressionsCount + referenceExpressionsCount == 2\n                }\n        } else {\n            true\n        }\n\n        if (areOnlyEnumEntriesWithExpressions && areOnlyEnumEntriesInRanges) {\n            return true\n        }\n        return false\n    }\n\n    private fun isStatement(node: ASTNode): Boolean {\n        // Checks if there is return before when\n        if (node.hasParent(RETURN)) {\n            return false\n        }\n\n        // Checks if `when` is the last statement in lambda body\n        if (node.treeParent.elementType == BLOCK && node.treeParent.treeParent.elementType == FUNCTION_LITERAL &&\n                node.treeParent.lastChildNode == node) {\n            return false\n        }\n\n        if (node.treeParent.elementType == WHEN_ENTRY && node.prevSibling { it.elementType == ARROW } != null) {\n            // `when` is used as a branch in another `when`\n            return false\n        }\n\n        return node.prevSibling { it.elementType == EQ || it.elementType == OPERATION_REFERENCE && it.firstChildNode.elementType == EQ }\n            ?.let {\n                // `when` is used in an assignment or in a function with expression body\n                false\n            }\n            ?: !node.hasParent(PROPERTY)\n    }\n\n    /**\n     * Check if this `when` has `else` branch. If `else` branch is empty, `(node.psi as KtWhenExpression).elseExpression` returns `null`,\n     * so we need to manually check if any entry contains `else` keyword.\n     */\n    private fun hasElse(node: ASTNode): Boolean = (node.psi as KtWhenExpression).entries.any { it.isElse }\n\n    private fun addChildren(node: ASTNode) {\n        val block = PsiBlockStatementImpl()\n\n        node.apply {\n            addChild(LeafPsiElement(ELSE_KEYWORD, \"else\"), null)\n            addChild(PsiWhiteSpaceImpl(\" \"), null)\n            addChild(LeafPsiElement(ARROW, \"->\"), null)\n            addChild(PsiWhiteSpaceImpl(\" \"), null)\n            addChild(block, null)\n        }\n\n        block.apply {\n            addChild(LeafPsiElement(LBRACE, \"{\"), null)\n            addChild(PsiWhiteSpaceImpl(\"\\n\"), null)\n            addChild(LeafPsiElement(EOL_COMMENT, \"// this is a generated else block\"), null)\n            addChild(PsiWhiteSpaceImpl(\"\\n\"), null)\n            addChild(LeafPsiElement(RBRACE, \"}\"), null)\n        }\n    }\n\n    companion object {\n        const val NAME_ID = \"no-else-in-when\"\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/main/kotlin/com/saveourtool/diktat/ruleset/rules/chapter3/files/BlankLinesRule.kt",
    "content": "package com.saveourtool.diktat.ruleset.rules.chapter3.files\n\nimport com.saveourtool.diktat.common.config.rules.RulesConfig\nimport com.saveourtool.diktat.ruleset.constants.Warnings.TOO_MANY_BLANK_LINES\nimport com.saveourtool.diktat.ruleset.rules.DiktatRule\nimport com.saveourtool.diktat.ruleset.utils.*\n\nimport org.jetbrains.kotlin.KtNodeTypes.BLOCK\nimport org.jetbrains.kotlin.KtNodeTypes.CLASS_BODY\nimport org.jetbrains.kotlin.KtNodeTypes.FUNCTION_LITERAL\nimport org.jetbrains.kotlin.KtNodeTypes.LAMBDA_ARGUMENT\nimport org.jetbrains.kotlin.KtNodeTypes.SCRIPT\nimport org.jetbrains.kotlin.com.intellij.lang.ASTNode\nimport org.jetbrains.kotlin.lexer.KtTokens.LBRACE\nimport org.jetbrains.kotlin.lexer.KtTokens.RBRACE\nimport org.jetbrains.kotlin.lexer.KtTokens.WHITE_SPACE\nimport org.jetbrains.kotlin.psi.stubs.elements.KtFileElementType\n\n/**\n * This rule checks usage of blank lines in code.\n * 1. Checks that no more than two consecutive blank lines are used in a row\n * 2. Checks that blank lines are not put in the beginning or at the end of code blocks with curly braces\n */\nclass BlankLinesRule(configRules: List<RulesConfig>) : DiktatRule(\n    NAME_ID,\n    configRules,\n    listOf(TOO_MANY_BLANK_LINES),\n) {\n    override fun logic(node: ASTNode) {\n        if (node.elementType == WHITE_SPACE) {\n            // note that no blank lines counts as one newline\n            if (node.numNewLines() == 2) {\n                handleBlankLine(node)\n            } else if (node.numNewLines() > 2) {\n                handleTooManyBlankLines(node)\n            }\n        }\n    }\n\n    private fun handleBlankLine(node: ASTNode) {\n        if (node.treeParent.let {\n            // kts files are parsed as a SCRIPT node containing BLOCK, therefore WHITE_SPACEs from these BLOCKS shouldn't be checked\n            it.elementType == BLOCK && it.treeParent?.elementType != SCRIPT ||\n                    it.elementType == CLASS_BODY || it.elementType == FUNCTION_LITERAL\n        }) {\n            node.findParentNodeWithSpecificType(LAMBDA_ARGUMENT)?.let {\n                // Lambda body is always has a BLOCK -> run { } - (LBRACE, WHITE_SPACE, BLOCK \"\", RBRACE)\n                if (node.treeNext.text.isEmpty()) {\n                    return\n                }\n            }\n\n            if ((node.treeNext.elementType == RBRACE) xor (node.treePrev.elementType == LBRACE)) {\n                // if both are present, this is not beginning or end\n                // if both are null, then this block is empty and is handled in another rule\n                val freeText = \"do not put newlines ${if (node.treePrev.elementType == LBRACE) \"in the beginning\" else \"at the end\"} of code blocks\"\n                TOO_MANY_BLANK_LINES.warnAndFix(configRules, emitWarn, isFixMode, freeText, node.startOffset, node) {\n                    node.leaveOnlyOneNewLine()\n                }\n            }\n        }\n    }\n\n    private fun handleTooManyBlankLines(node: ASTNode) {\n        TOO_MANY_BLANK_LINES.warnAndFix(configRules, emitWarn, isFixMode, \"do not use more than two consecutive blank lines\", node.startOffset, node) {\n            if (node.treeParent.elementType != KtFileElementType.INSTANCE && (node.treeParent.getFirstChildWithType(WHITE_SPACE) == node ||\n                    node.treeParent.getAllChildrenWithType(WHITE_SPACE).last() == node)) {\n                node.leaveExactlyNumNewLines(1)\n            } else {\n                node.leaveExactlyNumNewLines(2)\n            }\n        }\n    }\n\n    companion object {\n        const val NAME_ID = \"blank-lines\"\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/main/kotlin/com/saveourtool/diktat/ruleset/rules/chapter3/files/FileSize.kt",
    "content": "package com.saveourtool.diktat.ruleset.rules.chapter3.files\n\nimport com.saveourtool.diktat.common.config.rules.RuleConfiguration\nimport com.saveourtool.diktat.common.config.rules.RulesConfig\nimport com.saveourtool.diktat.common.config.rules.getRuleConfig\nimport com.saveourtool.diktat.ruleset.constants.Warnings.FILE_IS_TOO_LONG\nimport com.saveourtool.diktat.ruleset.rules.DiktatRule\n\nimport org.jetbrains.kotlin.com.intellij.lang.ASTNode\nimport org.jetbrains.kotlin.psi.stubs.elements.KtFileElementType\n\n/**\n * Rule that checks number of lines in a file\n */\nclass FileSize(configRules: List<RulesConfig>) : DiktatRule(\n    NAME_ID,\n    configRules,\n    listOf(FILE_IS_TOO_LONG)\n) {\n    private val configuration by lazy {\n        FileSizeConfiguration(\n            this.configRules.getRuleConfig(FILE_IS_TOO_LONG)?.configuration ?: emptyMap()\n        )\n    }\n\n    override fun logic(node: ASTNode) {\n        if (node.elementType == KtFileElementType.INSTANCE) {\n            checkFileSize(node, configuration.maxSize)\n        }\n    }\n\n    private fun checkFileSize(node: ASTNode, maxSize: Long) {\n        val size = node\n            .text\n            .split(\"\\n\")\n            .size\n        if (size > maxSize) {\n            FILE_IS_TOO_LONG.warn(configRules, emitWarn, size.toString(), node.startOffset, node)\n        }\n    }\n\n    /**\n     * [RuleConfiguration] for maximun number of lines in a file\n     */\n    class FileSizeConfiguration(config: Map<String, String>) : RuleConfiguration(config) {\n        /**\n         * Maximum allowed number of lines in a file\n         */\n        val maxSize = config[\"maxSize\"]?.toLongOrNull() ?: MAX_SIZE\n    }\n\n    companion object {\n        const val MAX_SIZE = 2000L\n        const val NAME_ID = \"file-size\"\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/main/kotlin/com/saveourtool/diktat/ruleset/rules/chapter3/files/FileStructureRule.kt",
    "content": "package com.saveourtool.diktat.ruleset.rules.chapter3.files\n\nimport com.saveourtool.diktat.common.config.rules.RuleConfiguration\nimport com.saveourtool.diktat.common.config.rules.RulesConfig\nimport com.saveourtool.diktat.common.config.rules.getCommonConfiguration\nimport com.saveourtool.diktat.common.config.rules.getRuleConfig\nimport com.saveourtool.diktat.ruleset.constants.Warnings.FILE_CONTAINS_ONLY_COMMENTS\nimport com.saveourtool.diktat.ruleset.constants.Warnings.FILE_INCORRECT_BLOCKS_ORDER\nimport com.saveourtool.diktat.ruleset.constants.Warnings.FILE_NO_BLANK_LINE_BETWEEN_BLOCKS\nimport com.saveourtool.diktat.ruleset.constants.Warnings.FILE_UNORDERED_IMPORTS\nimport com.saveourtool.diktat.ruleset.constants.Warnings.FILE_WILDCARD_IMPORTS\nimport com.saveourtool.diktat.ruleset.constants.Warnings.UNUSED_IMPORT\nimport com.saveourtool.diktat.ruleset.rules.DiktatRule\nimport com.saveourtool.diktat.ruleset.rules.chapter1.PackageNaming.Companion.PACKAGE_SEPARATOR\nimport com.saveourtool.diktat.ruleset.utils.StandardPlatforms\nimport com.saveourtool.diktat.ruleset.utils.copyrightWords\nimport com.saveourtool.diktat.ruleset.utils.findAllDescendantsWithSpecificType\nimport com.saveourtool.diktat.ruleset.utils.handleIncorrectOrder\nimport com.saveourtool.diktat.ruleset.utils.ignoreImports\nimport com.saveourtool.diktat.ruleset.utils.isPartOf\nimport com.saveourtool.diktat.ruleset.utils.isPartOfComment\nimport com.saveourtool.diktat.ruleset.utils.isWhiteSpace\nimport com.saveourtool.diktat.ruleset.utils.moveChildBefore\nimport com.saveourtool.diktat.ruleset.utils.nextSibling\nimport com.saveourtool.diktat.ruleset.utils.operatorMap\nimport com.saveourtool.diktat.ruleset.utils.prevSibling\n\nimport org.jetbrains.kotlin.KtNodeTypes.FILE_ANNOTATION_LIST\nimport org.jetbrains.kotlin.KtNodeTypes.IMPORT_DIRECTIVE\nimport org.jetbrains.kotlin.KtNodeTypes.IMPORT_LIST\nimport org.jetbrains.kotlin.KtNodeTypes.OPERATION_REFERENCE\nimport org.jetbrains.kotlin.KtNodeTypes.PACKAGE_DIRECTIVE\nimport org.jetbrains.kotlin.KtNodeTypes.REFERENCE_EXPRESSION\nimport org.jetbrains.kotlin.com.intellij.lang.ASTNode\nimport org.jetbrains.kotlin.com.intellij.psi.impl.source.tree.LeafPsiElement\nimport org.jetbrains.kotlin.com.intellij.psi.impl.source.tree.PsiWhiteSpaceImpl\nimport org.jetbrains.kotlin.com.intellij.psi.tree.TokenSet\nimport org.jetbrains.kotlin.kdoc.lexer.KDocTokens\nimport org.jetbrains.kotlin.kdoc.lexer.KDocTokens.KDOC\nimport org.jetbrains.kotlin.lexer.KtTokens.BLOCK_COMMENT\nimport org.jetbrains.kotlin.lexer.KtTokens.EOL_COMMENT\nimport org.jetbrains.kotlin.lexer.KtTokens.WHITE_SPACE\nimport org.jetbrains.kotlin.name.Name\nimport org.jetbrains.kotlin.psi.KtFile\nimport org.jetbrains.kotlin.psi.KtImportDirective\nimport org.jetbrains.kotlin.psi.KtPackageDirective\nimport org.jetbrains.kotlin.psi.psiUtil.children\nimport org.jetbrains.kotlin.psi.psiUtil.siblings\nimport org.jetbrains.kotlin.psi.stubs.elements.KtFileElementType\n\n/**\n * Visitor for checking internal file structure.\n * 1. Checks file contains not only comments\n * 2. Ensures the following blocks order: Copyright, Header Kdoc, @file annotation, package name, Import statements,\n *    top class header and top function header comments, top-level classes or top-level functions\n * 3. Ensures there is a blank line between these blocks\n * 4. Ensures imports are ordered alphabetically without blank lines\n * 5. Ensures there are no wildcard imports\n */\nclass FileStructureRule(configRules: List<RulesConfig>) : DiktatRule(\n    NAME_ID,\n    configRules,\n    listOf(FILE_CONTAINS_ONLY_COMMENTS, FILE_INCORRECT_BLOCKS_ORDER, FILE_NO_BLANK_LINE_BETWEEN_BLOCKS,\n        FILE_UNORDERED_IMPORTS, FILE_WILDCARD_IMPORTS, UNUSED_IMPORT),\n) {\n    private val domainName by lazy {\n        configRules\n            .getCommonConfiguration()\n            .domainName\n    }\n    private val standardImportsAsName = StandardPlatforms\n        .values()\n        .associate { it to it.packages }\n        .mapValues { (_, value) ->\n            value.map { it.split(PACKAGE_SEPARATOR).map(Name::identifier) }\n        }\n    private var packageName = \"\"\n\n    /**\n     * There are groups of methods, which should be excluded from usage check without type resolution.\n     * `componentN` is a method for N-th component in destructuring declarations.\n     */\n    private val ignoreImportsPatterns = setOf(\"component\\\\d+\".toRegex())\n\n    override fun logic(node: ASTNode) {\n        if (node.elementType == KtFileElementType.INSTANCE) {\n            val wildcardImportsConfig = WildCardImportsConfig(\n                this.configRules.getRuleConfig(FILE_WILDCARD_IMPORTS)?.configuration ?: emptyMap()\n            )\n            val importsGroupingConfig = ImportsGroupingConfig(\n                this.configRules.getRuleConfig(FILE_UNORDERED_IMPORTS)?.configuration ?: emptyMap()\n            )\n            checkUnusedImport(node)\n            node.findChildByType(IMPORT_LIST)\n                ?.let { checkImportsOrder(it, wildcardImportsConfig, importsGroupingConfig) }\n            if (checkFileHasCode(node)) {\n                checkCodeBlocksOrderAndEmptyLines(node)\n            }\n            return\n        }\n    }\n\n    @Suppress(\"FUNCTION_BOOLEAN_PREFIX\")\n    private fun checkFileHasCode(node: ASTNode): Boolean {\n        val codeTokens = TokenSet.andNot(\n            TokenSet.ANY,\n            TokenSet.create(WHITE_SPACE, KDOC, BLOCK_COMMENT, EOL_COMMENT, PACKAGE_DIRECTIVE, IMPORT_LIST)\n        )\n        val hasCode = node.getChildren(codeTokens).isNotEmpty()\n        if (!hasCode) {\n            val freeText = if (node.text.isEmpty()) \"file is empty\" else \"file contains no code\"\n            FILE_CONTAINS_ONLY_COMMENTS.warn(configRules, emitWarn, freeText, node.startOffset, node)\n        }\n        return hasCode\n    }\n\n    @Suppress(\n        \"ComplexMethod\",\n        \"TOO_LONG_FUNCTION\",\n        \"SpreadOperator\"\n    )\n    private fun checkCodeBlocksOrderAndEmptyLines(node: ASTNode) {\n        // From KtFile.kt: 'scripts have no package directive, all other files must have package directives'.\n        // Kotlin compiler itself enforces it's position in the file if it is present.\n        // If package directive is missing in .kt file (default package), the node is still present in the AST.\n        val packageDirectiveNode = (node.psi as KtFile)\n            .packageDirective\n            ?.takeUnless { it.isRoot }\n            ?.node\n        // There is a private property node.psi.importLists, but it's size can't be > 1 in valid kotlin code. It exists to help in situations\n        // when, e.g. merge conflict marker breaks the imports list. We shouldn't handle this situation here.\n        val importsList = (node.psi as KtFile)\n            .importList\n            ?.takeIf { it.imports.isNotEmpty() }\n            ?.node\n\n        // this node will be an anchor with respect to which we will look for all other nodes\n        val firstCodeNode = packageDirectiveNode\n            ?: importsList\n            ?: node.children().firstOrNull {\n                // taking nodes with actual code\n                !it.isWhiteSpace() && !it.isPartOfComment() &&\n                        // but not the ones we are going to move\n                        it.elementType != FILE_ANNOTATION_LIST &&\n                        // if we are here, then IMPORT_LIST either is not present in the AST, or is empty. Either way, we don't need to select it.\n                        it.elementType != IMPORT_LIST &&\n                        // if we are here, then package is default and we don't need to select the empty PACKAGE_DIRECTIVE node.\n                        it.elementType != PACKAGE_DIRECTIVE\n            }\n            ?: return  // at this point it means the file contains only comments\n        // We consider the first block comment of the file to be the one that possibly contains copyright information.\n        var copyrightComment = firstCodeNode.prevSibling { it.elementType == BLOCK_COMMENT }\n            ?.takeIf { blockCommentNode ->\n                copyrightWords.any { blockCommentNode.text.contains(it, ignoreCase = true) }\n            }\n        // firstCodeNode could be:\n        // * package directive - in this case we looking for kdoc before package directive\n        // and if it doesn't exist, additionally looking for kdoc before imports list\n        // * imports list or actual code - if there is no kdoc before it, suppose that it is absent in file\n        var headerKdoc = firstCodeNode.prevSibling { it.elementType == KDocTokens.KDOC }\n            ?: if (firstCodeNode == packageDirectiveNode) importsList?.prevSibling { it.elementType == KDocTokens.KDOC } else null\n        // Annotations with target`file` can only be placed before `package` directive.\n        var fileAnnotations = node.findChildByType(FILE_ANNOTATION_LIST)\n        // We also collect all other elements that are placed on top of the file.\n        // These may be other comments, so we just place them before the code starts.\n        val otherNodesBeforeCode = firstCodeNode.siblings(forward = false)\n            .filterNot {\n                it.isWhiteSpace() ||\n                        it == copyrightComment || it == headerKdoc || it == fileAnnotations ||\n                        it.elementType == PACKAGE_DIRECTIVE\n            }\n            .toList()\n            .reversed()\n\n        // checking order\n        listOfNotNull(copyrightComment, headerKdoc, fileAnnotations, *otherNodesBeforeCode.toTypedArray()).handleIncorrectOrder({\n            getSiblingBlocks(copyrightComment, headerKdoc, fileAnnotations, firstCodeNode, otherNodesBeforeCode)\n        }) { astNode, beforeThisNode ->\n            FILE_INCORRECT_BLOCKS_ORDER.warnAndFix(configRules, emitWarn, isFixMode, astNode.text.lines().first(), astNode.startOffset, astNode) {\n                val result = node.moveChildBefore(astNode, beforeThisNode, true)\n                result.newNodes.first().run {\n                    // reassign values to the nodes that could have been moved\n                    when (elementType) {\n                        BLOCK_COMMENT -> copyrightComment = this\n                        KDOC -> headerKdoc = this\n                        FILE_ANNOTATION_LIST -> fileAnnotations = this\n                    }\n                }\n                astNode.treeNext?.let { node.replaceChild(it, PsiWhiteSpaceImpl(\"\\n\\n\")) }\n            }\n        }\n\n        // checking empty lines\n        insertNewlinesBetweenBlocks(listOf(copyrightComment, headerKdoc, fileAnnotations, packageDirectiveNode, importsList))\n    }\n\n    @Suppress(\"UnsafeCallOnNullableType\")\n    private fun checkImportsOrder(\n        node: ASTNode,\n        wildCardImportsConfig: WildCardImportsConfig,\n        importsGroupingConfig: ImportsGroupingConfig\n    ) {\n        val imports = node.getChildren(TokenSet.create(IMPORT_DIRECTIVE)).toList()\n        // importPath can be null if import name cannot be parsed, which should be a very rare case, therefore !! should be safe here\n        @Suppress(\"PARAMETER_NAME_IN_OUTER_LAMBDA\")\n        imports\n            .filter {\n                (it.psi as KtImportDirective).importPath!!.run {\n                    isAllUnder && toString() !in wildCardImportsConfig.allowedWildcards\n                }\n            }\n            .forEach { FILE_WILDCARD_IMPORTS.warn(configRules, emitWarn, it.text, it.startOffset, it) }\n        val sortedImportsGroups = if (importsGroupingConfig.useRecommendedImportsOrder) {\n            regroupImports(imports.map { it.psi as KtImportDirective })\n                .map { group -> group.map { it.node } }\n        } else {\n            listOf(imports)\n        }\n            .map { group -> group.sortedBy { it.text } }\n        if (sortedImportsGroups.flatten() != imports) {\n            FILE_UNORDERED_IMPORTS.warnAndFix(configRules, emitWarn, isFixMode, \"${sortedImportsGroups.flatten().first().text}...\", node.startOffset, node) {\n                rearrangeImports(node, imports, sortedImportsGroups)\n            }\n        }\n    }\n\n    @Suppress(\"UnsafeCallOnNullableType\")\n    private fun checkUnusedImport(\n        node: ASTNode\n    ) {\n        val refSet = findAllReferences(node)\n        packageName = (node.findChildByType(PACKAGE_DIRECTIVE)?.psi as KtPackageDirective).qualifiedName\n        node.findChildByType(IMPORT_LIST)\n            ?.getChildren(TokenSet.create(IMPORT_DIRECTIVE))\n            ?.toList()\n            ?.forEach { import ->\n                val ktImportDirective = import.psi as KtImportDirective\n                val importName = ktImportDirective.importPath?.importedName?.asString()\n                val importPath = ktImportDirective.importPath?.pathStr!!  // importPath - ifNOtParsed & Nullable\n                if (ktImportDirective.aliasName == null &&\n                        packageName.isNotEmpty() && importPath.startsWith(\"$packageName.\") &&\n                        importPath.substring(packageName.length + 1).indexOf('.') == -1\n                ) {\n                    // this branch corresponds to imports from the same package\n                    deleteImport(importPath, node, ktImportDirective)\n                } else if (importName != null && !refSet.contains(importName)) {\n                    // Fixme: operatorMap imports and `getValue` should be deleted if unused, but we can't detect for sure\n                    val shouldImportBeIgnored = ignoreImports.contains(importName) || ignoreImportsPatterns.any { it.matches(importName) }\n                    if (!shouldImportBeIgnored) {\n                        // this import is not used anywhere\n                        deleteImport(importPath, node, ktImportDirective)\n                    }\n                }\n            }\n    }\n\n    private fun deleteImport(\n        importPath: String,\n        node: ASTNode,\n        ktImportDirective: KtImportDirective\n    ) {\n        UNUSED_IMPORT.warnAndFix(\n            configRules, emitWarn, isFixMode,\n            \"$importPath - unused import\",\n            node.startOffset, node\n        ) { ktImportDirective.delete() }\n    }\n\n    private fun findAllReferences(node: ASTNode): Set<String> {\n        val referencesFromOperations = node.findAllDescendantsWithSpecificType(OPERATION_REFERENCE)\n            .filterNot { it.isPartOf(IMPORT_DIRECTIVE) }\n            .flatMap { ref ->\n                val references = operatorMap.filterValues { ref.text in it }\n                if (references.isNotEmpty()) {\n                    references.keys\n                } else {\n                    // this is needed to check infix functions that relate to operation reference\n                    setOf(ref.text)\n                }\n            }\n        val referencesFromExpressions = node.findAllDescendantsWithSpecificType(REFERENCE_EXPRESSION)\n            .filterNot { it.isPartOf(IMPORT_DIRECTIVE) }\n            .map {\n                // the importedName method removes the quotes, but the node.text method does not\n                it.text.replace(\"`\", \"\")\n            }\n        val referencesFromKdocs = node.findAllDescendantsWithSpecificType(KDocTokens.KDOC)\n            .flatMap { it.findAllDescendantsWithSpecificType(KDocTokens.MARKDOWN_LINK) }\n            .map { it.text.removePrefix(\"[\").removeSuffix(\"]\") }\n            .flatMap {\n                if (it.contains(\".\")) {\n                    // support cases with reference to method\n                    listOf(it, it.substringBeforeLast(\".\"))\n                } else {\n                    listOf(it)\n                }\n            }\n        return (referencesFromOperations + referencesFromExpressions + referencesFromKdocs).toSet()\n    }\n\n    private fun rearrangeImports(\n        node: ASTNode,\n        imports: List<ASTNode>,\n        sortedImportsGroups: List<List<ASTNode>>\n    ) {\n        require(node.elementType == IMPORT_LIST)\n        // move all commented lines among import before imports block\n        node.getChildren(TokenSet.create(EOL_COMMENT))\n            .forEach {\n                node.treeParent.addChild(it.clone() as ASTNode, node)\n                node.treeParent.addChild(PsiWhiteSpaceImpl(\"\\n\"), node)\n            }\n\n        node.removeRange(imports.first(), imports.last())\n        sortedImportsGroups.filterNot { it.isEmpty() }\n            .run {\n                forEachIndexed { groupIndex, group ->\n                    group.forEachIndexed { index, importNode ->\n                        node.addChild(importNode, null)\n                        if (index != group.size - 1) {\n                            node.addChild(PsiWhiteSpaceImpl(\"\\n\"), null)\n                        }\n                    }\n                    if (groupIndex != size - 1) {\n                        node.addChild(PsiWhiteSpaceImpl(\"\\n\\n\"), null)\n                    }\n                }\n            }\n    }\n\n    private fun insertNewlinesBetweenBlocks(blocks: List<ASTNode?>) {\n        blocks.forEach { astNode ->\n            // if package directive is missing, node is still present, but it's text is empty, so we need to check treeNext to get meaningful results\n            astNode?.nextSibling { it.text.isNotEmpty() }?.apply {\n                if (elementType == WHITE_SPACE && text.count { it == '\\n' } != 2) {\n                    FILE_NO_BLANK_LINE_BETWEEN_BLOCKS.warnAndFix(configRules, emitWarn, isFixMode, astNode.text.lines().first(),\n                        astNode.startOffset, astNode) {\n                        (this as LeafPsiElement).rawReplaceWithText(\"\\n\\n${text.replace(\"\\n\", \"\")}\")\n                    }\n                }\n            }\n        }\n    }\n\n    /**\n     * @return a pair of nodes between which [this] node should be placed, i.e. after the first and before the second element\n     */\n    private fun ASTNode.getSiblingBlocks(\n        copyrightComment: ASTNode?,\n        headerKdoc: ASTNode?,\n        fileAnnotations: ASTNode?,\n        firstCodeNode: ASTNode,\n        otherNodesBeforeFirst: List<ASTNode>\n    ): Pair<ASTNode?, ASTNode> = when (this) {\n        copyrightComment -> null to listOfNotNull(headerKdoc, fileAnnotations, otherNodesBeforeFirst.firstOrNull(), firstCodeNode).first()\n        headerKdoc -> copyrightComment to (fileAnnotations ?: otherNodesBeforeFirst.firstOrNull() ?: firstCodeNode)\n        fileAnnotations -> (headerKdoc ?: copyrightComment) to (otherNodesBeforeFirst.firstOrNull() ?: firstCodeNode)\n        else -> (headerKdoc ?: copyrightComment) to firstCodeNode\n    }\n\n    @Suppress(\"TYPE_ALIAS\", \"UnsafeCallOnNullableType\")\n    private fun regroupImports(imports: List<KtImportDirective>): List<List<KtImportDirective>> {\n        val (android, notAndroid) = imports.partition {\n            it.isStandard(StandardPlatforms.ANDROID)\n        }\n\n        val (ownDomain, tmp) = domainName?.let { domainName ->\n            notAndroid.partition { import ->\n                import\n                    .importPath\n                    ?.fqName\n                    ?.pathSegments()\n                    ?.zip(domainName.split(PACKAGE_SEPARATOR).map(Name::identifier))\n                    ?.all { it.first == it.second }\n                    ?: false\n            }\n        } ?: Pair(emptyList(), notAndroid)\n\n        val (others, javaAndKotlin) = tmp.partition {\n            !it.isStandard(StandardPlatforms.JAVA) && !it.isStandard(StandardPlatforms.KOTLIN)\n        }\n\n        val (java, kotlin) = javaAndKotlin.partition { it.isStandard(StandardPlatforms.JAVA) }\n\n        return listOf(android, ownDomain, others, java, kotlin)\n    }\n\n    private fun KtImportDirective.isStandard(platformName: StandardPlatforms) = standardImportsAsName[platformName]?.any { names ->\n        names.zip(importPath?.fqName?.pathSegments() ?: emptyList())\n            .all { it.first == it.second }\n    } ?: false\n\n    /**\n     * [RuleConfiguration] for wildcard imports\n     */\n    class WildCardImportsConfig(config: Map<String, String>) : RuleConfiguration(config) {\n        /**\n         * A list of imports that are allowed to use wildcards. Input is in a form \"foo.bar.*,foo.baz.*\".\n         */\n        val allowedWildcards = config[\"allowedWildcards\"]?.split(\",\")?.map { it.trim() } ?: emptyList()\n    }\n\n    /**\n     * [RuleConfiguration] for imports grouping according to the recommendation from diktat code style\n     */\n    class ImportsGroupingConfig(config: Map<String, String>) : RuleConfiguration(config) {\n        /**\n         * Use imports grouping according to recommendation 3.1\n         */\n        val useRecommendedImportsOrder = config[\"useRecommendedImportsOrder\"]?.toBoolean() ?: true\n    }\n\n    companion object {\n        const val NAME_ID = \"file-structure\"\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/main/kotlin/com/saveourtool/diktat/ruleset/rules/chapter3/files/IndentationAmount.kt",
    "content": "package com.saveourtool.diktat.ruleset.rules.chapter3.files\n\nimport com.saveourtool.diktat.ruleset.utils.indentation.IndentationConfig\n\n/**\n * Encapsulates the change in the indentation level.\n */\n@Suppress(\"WRONG_DECLARATIONS_ORDER\")\ninternal enum class IndentationAmount {\n    /**\n     * The indent should be preserved at the current level.\n     */\n    NONE,\n\n    /**\n     * The indent should be increased or decreased by 1 (regular single indent).\n     */\n    SINGLE,\n\n    /**\n     * Extended, or _continuation_ indent. Applicable when any of\n     * [`extendedIndent*`][IndentationConfig] flags is **on**.\n     */\n    EXTENDED,\n    ;\n\n    /**\n     * @return the indentation level. To get the actual indentation (the amount\n     *   of space characters), the value needs to be multiplied by\n     *   [IndentationConfig.indentationSize].\n     * @see IndentationConfig.indentationSize\n     */\n    fun level(): Int =\n        ordinal\n\n    /**\n     * @return whether this amount represents the change in the indentation\n     *   level, i.e. whether the element should be indented or un-indented.\n     */\n    fun isNonZero(): Boolean =\n        level() > 0\n\n    companion object {\n        /**\n         * A convenience factory method.\n         *\n         * @param extendedIndent the actual value of ony of the `extendedIndent*`\n         *   flags.\n         * @return the corresponding indentation amount, either [SINGLE] or\n         *   [EXTENDED].\n         */\n        @JvmStatic\n        fun valueOf(extendedIndent: Boolean): IndentationAmount =\n            when {\n                extendedIndent -> EXTENDED\n                else -> SINGLE\n            }\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/main/kotlin/com/saveourtool/diktat/ruleset/rules/chapter3/files/IndentationAware.kt",
    "content": "package com.saveourtool.diktat.ruleset.rules.chapter3.files\n\n/**\n * A contract for types which encapsulate the indentation level.\n */\ninternal interface IndentationAware {\n    /**\n     * @return the indentation (the amount of space characters) of this element.\n     */\n    val indentation: Int\n}\n"
  },
  {
    "path": "diktat-rules/src/main/kotlin/com/saveourtool/diktat/ruleset/rules/chapter3/files/IndentationConfigAware.kt",
    "content": "package com.saveourtool.diktat.ruleset.rules.chapter3.files\n\nimport com.saveourtool.diktat.ruleset.utils.indentation.IndentationConfig\n\n/**\n * Higher-level abstractions on top of the [indentation size][IndentationConfig.indentationSize].\n */\ninternal interface IndentationConfigAware {\n    /**\n     * The configuration this instance encapsulates.\n     */\n    val configuration: IndentationConfig\n\n    /**\n     * Increases the indentation level by [level] * [IndentationConfig.indentationSize].\n     *\n     * This extension doesn't modify the receiver.\n     *\n     * @receiver the previous indentation level (in space characters), not\n     *   modified by the function call.\n     * @param level the indentation level, 1 by default.\n     * @return the new indentation level.\n     * @see unindent\n     * @see IndentationConfig.indentationSize\n     */\n    fun Int.indent(level: Int = 1): Int =\n        this + level * configuration.indentationSize\n\n    /**\n     * Decreases the indentation level by [level] * [IndentationConfig.indentationSize].\n     *\n     * This extension doesn't modify the receiver.\n     *\n     * @receiver the previous indentation level (in space characters), not\n     *   modified by the function call.\n     * @param level the indentation level, 1 by default.\n     * @return the new indentation level.\n     * @see indent\n     * @see IndentationConfig.indentationSize\n     */\n    fun Int.unindent(level: Int = 1): Int =\n        indent(-level)\n\n    /**\n     * @receiver the previous indentation level (in space characters), not\n     *   modified by the function call.\n     * @param amount the indentation amount.\n     * @return the new (increased) indentation level.\n     * @see minus\n     */\n    operator fun Int.plus(amount: IndentationAmount): Int =\n        indent(level = amount.level())\n\n    /**\n     * @receiver the previous indentation level (in space characters), not\n     *   modified by the function call.\n     * @param amount the indentation amount.\n     * @return the new (decreased) indentation level.\n     * @see plus\n     */\n    operator fun Int.minus(amount: IndentationAmount): Int =\n        unindent(level = amount.level())\n\n    /**\n     * Allows the `+` operation between an Int and an IndentationAmount to be\n     * commutative. Now, the following are equivalent:\n     *\n     * ```kotlin\n     * val i = 42 + IndentationAmount.SINGLE\n     * val j = IndentationAmount.SINGLE + 42\n     * ```\n     *\n     * &mdash; as are these:\n     *\n     * ```kotlin\n     * val i = 42 + IndentationAmount.SINGLE\n     * val j = IndentationAmount.SINGLE + 42\n     * ```\n     *\n     * @receiver the indentation amount.\n     * @param indentationSpaces the indentation level (in space characters).\n     * @return the new (increased) indentation level.\n     * @see IndentationAmount.minus\n     */\n    operator fun IndentationAmount.plus(indentationSpaces: Int): Int =\n        indentationSpaces + this\n\n    /**\n     * Allows expressions like this:\n     *\n     * ```kotlin\n     * 42 - IndentationAmount.SINGLE + 4\n     * ```\n     *\n     * to be rewritten this way:\n     *\n     * ```kotlin\n     * 42 - (IndentationAmount.SINGLE - 4)\n     * ```\n     *\n     * @receiver the indentation amount.\n     * @param indentationSpaces the indentation level (in space characters).\n     * @return the new (decreased) indentation level.\n     * @see IndentationAmount.plus\n     */\n    operator fun IndentationAmount.minus(indentationSpaces: Int): Int =\n        this + (-indentationSpaces)\n\n    /**\n     * @receiver the 1st term.\n     * @param other the 2nd term.\n     * @return the two indentation amounts combined, as the indentation level\n     *   (in space characters).\n     * @see IndentationAmount.minus\n     */\n    operator fun IndentationAmount.plus(other: IndentationAmount): Int =\n        this + (+other)\n\n    /**\n     * @receiver the minuend.\n     * @param other the subtrahend.\n     * @return one amount subtracted from the other, as the indentation level\n     *   (in space characters).\n     * @see IndentationAmount.plus\n     */\n    operator fun IndentationAmount.minus(other: IndentationAmount): Int =\n        this + (-other)\n\n    /**\n     * @receiver the indentation amount.\n     * @return the indentation level (in space characters).\n     * @see IndentationAmount.unaryMinus\n     */\n    operator fun IndentationAmount.unaryPlus(): Int =\n        level() * configuration.indentationSize\n\n    /**\n     * @receiver the indentation amount.\n     * @return the negated indentation level (in space characters).\n     * @see IndentationAmount.unaryPlus\n     */\n    operator fun IndentationAmount.unaryMinus(): Int =\n        -(+this)\n\n    companion object Factory {\n        /**\n         * Creates a new instance.\n         *\n         * While you may call this function directly, consider using\n         * [withIndentationConfig] instead.\n         *\n         * @param configuration the configuration this instance will wrap.\n         * @return the newly created instance.\n         * @see withIndentationConfig\n         */\n        operator fun invoke(configuration: IndentationConfig): IndentationConfigAware =\n            object : IndentationConfigAware {\n                override val configuration = configuration\n            }\n\n        /**\n         * Calls the specified function [block] with [IndentationConfigAware] as\n         * its receiver and returns its result.\n         *\n         * @param configuration the configuration for the indentation rule.\n         * @param block the function block to call.\n         * @return the result returned by the function block.\n         */\n        inline fun <T> withIndentationConfig(configuration: IndentationConfig,\n                                             block: IndentationConfigAware.() -> T): T =\n            with(IndentationConfigAware(configuration), block)\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/main/kotlin/com/saveourtool/diktat/ruleset/rules/chapter3/files/IndentationError.kt",
    "content": "package com.saveourtool.diktat.ruleset.rules.chapter3.files\n\n/**\n * @property expected expected indentation as a number of spaces\n * @property actual actual indentation as a number of spaces\n */\ninternal data class IndentationError(val expected: Int, val actual: Int)\n"
  },
  {
    "path": "diktat-rules/src/main/kotlin/com/saveourtool/diktat/ruleset/rules/chapter3/files/IndentationRule.kt",
    "content": "/**\n * Main logic of indentation including Rule and utility classes and methods.\n */\n\n@file:Suppress(\"FILE_UNORDERED_IMPORTS\")// False positives, see #1494.\n\npackage com.saveourtool.diktat.ruleset.rules.chapter3.files\n\nimport com.saveourtool.diktat.api.DiktatErrorEmitter\nimport com.saveourtool.diktat.common.config.rules.RulesConfig\nimport com.saveourtool.diktat.common.config.rules.getRuleConfig\nimport com.saveourtool.diktat.ruleset.constants.Warnings.WRONG_INDENTATION\nimport com.saveourtool.diktat.ruleset.rules.DiktatRule\nimport com.saveourtool.diktat.ruleset.rules.chapter3.files.IndentationAmount.NONE\nimport com.saveourtool.diktat.ruleset.rules.chapter3.files.IndentationAmount.SINGLE\nimport com.saveourtool.diktat.ruleset.rules.chapter3.files.IndentationConfigAware.Factory.withIndentationConfig\nimport com.saveourtool.diktat.ruleset.utils.NEWLINE\nimport com.saveourtool.diktat.ruleset.utils.SPACE\nimport com.saveourtool.diktat.ruleset.utils.TAB\nimport com.saveourtool.diktat.ruleset.utils.getAllChildrenWithType\nimport com.saveourtool.diktat.ruleset.utils.getAllLeafsWithSpecificType\nimport com.saveourtool.diktat.ruleset.utils.getFilePath\nimport com.saveourtool.diktat.ruleset.utils.getFirstChildWithType\nimport com.saveourtool.diktat.ruleset.utils.indentBy\nimport com.saveourtool.diktat.ruleset.utils.indentation.ArrowInWhenChecker\nimport com.saveourtool.diktat.ruleset.utils.indentation.AssignmentOperatorChecker\nimport com.saveourtool.diktat.ruleset.utils.indentation.ConditionalsAndLoopsWithoutBracesChecker\nimport com.saveourtool.diktat.ruleset.utils.indentation.CustomGettersAndSettersChecker\nimport com.saveourtool.diktat.ruleset.utils.indentation.CustomIndentationChecker\nimport com.saveourtool.diktat.ruleset.utils.indentation.DotCallChecker\nimport com.saveourtool.diktat.ruleset.utils.indentation.ExpressionIndentationChecker\nimport com.saveourtool.diktat.ruleset.utils.indentation.IndentationConfig\nimport com.saveourtool.diktat.ruleset.utils.indentation.KdocIndentationChecker\nimport com.saveourtool.diktat.ruleset.utils.indentation.SuperTypeListChecker\nimport com.saveourtool.diktat.ruleset.utils.indentation.ValueParameterListChecker\nimport com.saveourtool.diktat.ruleset.utils.lastIndent\nimport com.saveourtool.diktat.ruleset.utils.leadingSpaceCount\nimport com.saveourtool.diktat.ruleset.utils.leaveOnlyOneNewLine\nimport com.saveourtool.diktat.ruleset.utils.visit\n\nimport org.jetbrains.kotlin.KtNodeTypes.BINARY_EXPRESSION\nimport org.jetbrains.kotlin.KtNodeTypes.CALL_EXPRESSION\nimport org.jetbrains.kotlin.lexer.KtTokens.CLOSING_QUOTE\nimport org.jetbrains.kotlin.KtNodeTypes.DOT_QUALIFIED_EXPRESSION\nimport org.jetbrains.kotlin.KtNodeTypes.ELSE\nimport org.jetbrains.kotlin.lexer.KtTokens.IDENTIFIER\nimport org.jetbrains.kotlin.lexer.KtTokens.LBRACE\nimport org.jetbrains.kotlin.lexer.KtTokens.LBRACKET\nimport org.jetbrains.kotlin.KtNodeTypes.LITERAL_STRING_TEMPLATE_ENTRY\nimport org.jetbrains.kotlin.KtNodeTypes.LONG_STRING_TEMPLATE_ENTRY\nimport org.jetbrains.kotlin.lexer.KtTokens.LONG_TEMPLATE_ENTRY_END\nimport org.jetbrains.kotlin.lexer.KtTokens.LONG_TEMPLATE_ENTRY_START\nimport org.jetbrains.kotlin.lexer.KtTokens.LPAR\nimport org.jetbrains.kotlin.KtNodeTypes.PARENTHESIZED\nimport org.jetbrains.kotlin.lexer.KtTokens.RBRACE\nimport org.jetbrains.kotlin.lexer.KtTokens.RBRACKET\nimport org.jetbrains.kotlin.KtNodeTypes.REFERENCE_EXPRESSION\nimport org.jetbrains.kotlin.lexer.KtTokens.REGULAR_STRING_PART\nimport org.jetbrains.kotlin.lexer.KtTokens.RPAR\nimport org.jetbrains.kotlin.KtNodeTypes.SAFE_ACCESS_EXPRESSION\nimport org.jetbrains.kotlin.KtNodeTypes.SHORT_STRING_TEMPLATE_ENTRY\nimport org.jetbrains.kotlin.KtNodeTypes.STRING_TEMPLATE\nimport org.jetbrains.kotlin.KtNodeTypes.THEN\nimport org.jetbrains.kotlin.KtNodeTypes.VALUE_ARGUMENT\nimport org.jetbrains.kotlin.KtNodeTypes.VALUE_ARGUMENT_LIST\nimport org.jetbrains.kotlin.KtNodeTypes.VALUE_PARAMETER_LIST\nimport org.jetbrains.kotlin.lexer.KtTokens.WHITE_SPACE\nimport com.saveourtool.diktat.ruleset.utils.isWhiteSpaceWithNewline\nimport io.github.oshai.kotlinlogging.KotlinLogging\nimport org.jetbrains.kotlin.com.intellij.lang.ASTNode\nimport org.jetbrains.kotlin.com.intellij.psi.PsiWhiteSpace\nimport org.jetbrains.kotlin.com.intellij.psi.impl.source.tree.LeafPsiElement\nimport org.jetbrains.kotlin.com.intellij.psi.impl.source.tree.PsiWhiteSpaceImpl\nimport org.jetbrains.kotlin.com.intellij.psi.tree.IElementType\nimport org.jetbrains.kotlin.konan.file.File\nimport org.jetbrains.kotlin.psi.KtDotQualifiedExpression\nimport org.jetbrains.kotlin.psi.KtIfExpression\nimport org.jetbrains.kotlin.psi.KtLoopExpression\nimport org.jetbrains.kotlin.psi.psiUtil.parents\nimport org.jetbrains.kotlin.psi.psiUtil.parentsWithSelf\nimport org.jetbrains.kotlin.psi.psiUtil.startOffset\nimport org.jetbrains.kotlin.psi.stubs.elements.KtFileElementType\n\nimport kotlin.contracts.ExperimentalContracts\nimport kotlin.contracts.contract\nimport kotlin.reflect.KCallable\n\nimport java.util.ArrayDeque as Stack\n\n/**\n * Rule that checks indentation. The following general rules are checked:\n * 1. Only spaces should be used each indentation is equal to 4 spaces\n * 2. File should end with new line\n * Additionally, a set of CustomIndentationChecker objects checks all WHITE_SPACE node if they are exceptions from general rules.\n * @see CustomIndentationChecker\n */\n@Suppress(\"LargeClass\")\nclass IndentationRule(configRules: List<RulesConfig>) : DiktatRule(\n    NAME_ID,\n    configRules,\n    listOf(WRONG_INDENTATION)\n) {\n    private val configuration: IndentationConfig by lazy {\n        IndentationConfig(configRules.getRuleConfig(WRONG_INDENTATION)?.configuration ?: emptyMap())\n    }\n    private lateinit var filePath: String\n    private lateinit var customIndentationCheckers: List<CustomIndentationChecker>\n    private lateinit var overriddenEmitWarn: DiktatErrorEmitter\n\n    override fun logic(node: ASTNode) {\n        overriddenEmitWarn = configuration.overrideIfRequiredWarnMessage(emitWarn)\n        if (node.elementType == KtFileElementType.INSTANCE) {\n            filePath = node.getFilePath()\n\n            customIndentationCheckers = listOf(\n                ::AssignmentOperatorChecker,\n                ::ConditionalsAndLoopsWithoutBracesChecker,\n                ::SuperTypeListChecker,\n                ::ValueParameterListChecker,\n                ::ExpressionIndentationChecker,\n                ::DotCallChecker,\n                ::KdocIndentationChecker,\n                ::CustomGettersAndSettersChecker,\n                ::ArrowInWhenChecker\n            ).map { it(configuration) }\n\n            if (checkIsIndentedWithSpaces(node)) {\n                checkIndentation(node)\n            } else {\n                log.warn { \"Not going to check indentation because there are tabs\" }\n            }\n            checkNewlineAtEnd(node)\n        }\n    }\n\n    /**\n     * This method warns if tabs are used in WHITE_SPACE nodes and substitutes them with spaces in fix mode\n     *\n     * @return true if there are no tabs or all of them have been fixed, false otherwise\n     */\n    @Suppress(\"FUNCTION_BOOLEAN_PREFIX\")\n    private fun checkIsIndentedWithSpaces(node: ASTNode): Boolean {\n        val whiteSpaceNodes: MutableList<ASTNode> = mutableListOf()\n        node.getAllLeafsWithSpecificType(WHITE_SPACE, whiteSpaceNodes)\n        whiteSpaceNodes\n            .filter { it.textContains(TAB) }\n            .apply {\n                if (isEmpty()) {\n                    return true\n                }\n            }\n            .forEach { whiteSpaceNode ->\n                WRONG_INDENTATION.warnAndFix(configRules, overriddenEmitWarn, isFixMode, \"tabs are not allowed for indentation\",\n                    whiteSpaceNode.startOffset + whiteSpaceNode.text.indexOf(TAB), whiteSpaceNode) {\n                    (whiteSpaceNode as LeafPsiElement).rawReplaceWithText(whiteSpaceNode.text.replace(TAB.toString(), configuration.indentationSize.spaces))\n                }\n            }\n        return isFixMode  // true if we changed all tabs to spaces\n    }\n\n    /**\n     * Checks that file ends with exactly one empty line\n     */\n    private fun checkNewlineAtEnd(node: ASTNode) {\n        if (configuration.newlineAtEnd) {\n            val lastChild = generateSequence(node) { it.lastChildNode }.last()\n            val numBlankLinesAfter = lastChild.text.count { it == NEWLINE }\n            if (lastChild.elementType != WHITE_SPACE || numBlankLinesAfter != 1) {\n                val warnText = if (lastChild.elementType != WHITE_SPACE || numBlankLinesAfter == 0) \"no newline\" else \"too many blank lines\"\n                val fileName = filePath.substringAfterLast(File.separator)\n                // In case, when last child is newline, visually user will see blank line at the end of file,\n                // however, the text length does not consider it, since it's blank and line appeared only because of `\\n`\n                // But ktlint synthetically increase length in aim to have ability to point to this line, so in this case\n                // offset will be `node.textLength`, otherwise we will point to the last symbol, i.e `node.textLength - 1`\n                val offset = if (lastChild.isMultilineWhitespace()) node.textLength else node.textLength - 1\n                WRONG_INDENTATION.warnAndFix(configRules, overriddenEmitWarn, isFixMode, \"$warnText at the end of file $fileName\", offset, node) {\n                    if (lastChild.elementType != WHITE_SPACE) {\n                        node.addChild(PsiWhiteSpaceImpl(NEWLINE.toString()), null)\n                    } else {\n                        lastChild.leaveOnlyOneNewLine()\n                    }\n                }\n            }\n        }\n    }\n\n    /**\n     * Traverses the tree, keeping track of regular and exceptional indentations\n     */\n    private fun checkIndentation(node: ASTNode) =\n        with(IndentContext(configuration)) {\n            node.visit { astNode ->\n                checkAndReset(astNode)\n                val indentationIncrement = astNode.getIndentationIncrement()\n                if (indentationIncrement.isNonZero()) {\n                    storeIncrementingToken(astNode.elementType, indentationIncrement)\n                } else if (astNode.getIndentationDecrement().isNonZero() && !astNode.treePrev.isMultilineWhitespace()) {\n                    // if decreasing token is after WHITE_SPACE with \\n, indents are corrected in visitWhiteSpace method\n                    this -= astNode.elementType\n                } else if (astNode.isMultilineWhitespace() && astNode.treeNext != null) {\n                    // we check only WHITE_SPACE nodes with newlines, other than the last line in file; correctness of newlines should be checked elsewhere\n                    visitWhiteSpace(astNode)\n                }\n            }\n        }\n\n    @Suppress(\"ForbiddenComment\")\n    private fun IndentContext.visitWhiteSpace(astNode: ASTNode) {\n        require(astNode.isMultilineWhitespace()) {\n            \"The node is $astNode while a multi-line $WHITE_SPACE expected\"\n        }\n\n        maybeIncrement()\n        val whiteSpace = astNode.psi as PsiWhiteSpace\n        if (astNode.treeNext.getIndentationDecrement().isNonZero()) {\n            // if newline is followed by closing token, it should already be indented less\n            this -= astNode.treeNext.elementType\n        }\n\n        val indentError = IndentationError(indentation, astNode.text.lastIndent())\n\n        val checkResult = customIndentationCheckers.firstNotNullOfOrNull {\n            it.checkNode(whiteSpace, indentError)\n        }\n\n        val expectedIndent = checkResult?.expectedIndent ?: indentError.expected\n        if (checkResult?.adjustNext == true && astNode.parents().none { it.elementType == LONG_STRING_TEMPLATE_ENTRY }) {\n            val exceptionInitiatorNode = astNode.getExceptionalIndentInitiator()\n            addException(exceptionInitiatorNode, expectedIndent - indentError.expected, checkResult.includeLastChild)\n        }\n\n        if (astNode.treeParent.elementType == LONG_STRING_TEMPLATE_ENTRY && astNode.treeNext.elementType != LONG_TEMPLATE_ENTRY_END) {\n            addException(astNode.treeParent, SINGLE.level() * configuration.indentationSize, false)\n        }\n\n        val alignedOpeningAndClosingQuotes = hasAlignedOpeningAndClosingQuotes(astNode, indentError.actual)\n\n        if ((checkResult?.isCorrect != true && expectedIndent != indentError.actual) || !alignedOpeningAndClosingQuotes) {\n            val warnText = if (!alignedOpeningAndClosingQuotes) {\n                \"the same number of indents to the opening and closing quotes was expected\"\n            } else {\n                \"expected $expectedIndent but was ${indentError.actual}\"\n            }\n            WRONG_INDENTATION.warnAndFix(configRules, overriddenEmitWarn, isFixMode, warnText,\n                whiteSpace.startOffset + whiteSpace.text.lastIndexOf(NEWLINE) + 1, whiteSpace.node) {\n                checkStringLiteral(whiteSpace, expectedIndent, indentError.actual)\n                whiteSpace.node.indentBy(expectedIndent)\n            }\n        }\n    }\n\n    /**\n     * Checks if it is a triple-quoted string template with\n     * [trimIndent()][String.trimIndent] or [trimMargin(...)][String.trimMargin]\n     * function.\n     */\n    private fun checkStringLiteral(\n        whiteSpace: PsiWhiteSpace,\n        expectedIndent: Int,\n        actualIndent: Int\n    ) {\n        val nextNodeDot = whiteSpace.node.treeNext.getNextDotExpression()\n        if (nextNodeDot != null &&\n                nextNodeDot.elementType == DOT_QUALIFIED_EXPRESSION &&\n                nextNodeDot.firstChildNode.elementType == STRING_TEMPLATE &&\n                nextNodeDot.firstChildNode.text.startsWith(\"\\\"\\\"\\\"\") &&\n                nextNodeDot.findChildByType(CALL_EXPRESSION).isTrimIndentOrMarginCall()) {\n            fixStringLiteral(nextNodeDot.firstChildNode, expectedIndent, actualIndent)\n        }\n    }\n\n    /**\n     * Indents each [entry][LITERAL_STRING_TEMPLATE_ENTRY] in a (potentially,\n     * multi-line) triple-quoted [string template][STRING_TEMPLATE].\n     *\n     * String templates usually have the following structure:\n     *\n     * * `STRING_TEMPLATE`\n     *    * `OPEN_QUOTE`\n     *    * `LITERAL_STRING_TEMPLATE_ENTRY`\n     *       * `REGULAR_STRING_PART`\n     *    * &#x2026;\n     *    * `LITERAL_STRING_TEMPLATE_ENTRY`\n     *       * `REGULAR_STRING_PART`\n     *    * `CLOSING_QUOTE`\n     *\n     * @param stringTemplate the string template.\n     * @see STRING_TEMPLATE\n     * @see LITERAL_STRING_TEMPLATE_ENTRY\n     */\n    @Suppress(\"LOCAL_VARIABLE_EARLY_DECLARATION\")\n    private fun fixStringLiteral(\n        stringTemplate: ASTNode,\n        expectedIndent: Int,\n        actualIndent: Int\n    ) {\n        val templateEntries = stringTemplate.getAllChildrenWithType(LITERAL_STRING_TEMPLATE_ENTRY)\n        val templateEntriesLastIndex = templateEntries.size - 1\n        var templateEntryFollowingNewline = false\n\n        templateEntries.forEachIndexed { index, templateEntry ->\n            val text = templateEntry.text\n\n            when {\n                text.contains(NEWLINE) -> {\n                    /*\n                     * Set the flag.\n                     */\n                    templateEntryFollowingNewline = true\n\n                    /*\n                     * In real-life cases observed, whenever a `LITERAL_STRING_TEMPLATE_ENTRY`\n                     * _contains_ a newline character, it is _exactly_ a newline character.\n                     */\n                    check(text.length == 1) {\n                        val escapedText = text.replace(NEWLINE.toString(), \"\\\\n\")\n\n                        \"A LITERAL_STRING_TEMPLATE_ENTRY at index $index contains extra characters in addition to the newline, \" +\n                                \"entry: \\\"$escapedText\\\", \" +\n                                \"string template: ${stringTemplate.text}\"\n                    }\n                }\n\n                /*\n                 * This is the last string template fragment which is usually followed\n                 * with the closing `\"\"\"` and the `.trimIndent()` or `.trimMargin(...)` call.\n                 */\n                index == templateEntriesLastIndex -> {\n                    val lastRegularStringPart = templateEntries.last().firstChildNode as LeafPsiElement\n                    lastRegularStringPart.checkRegularStringPart().apply {\n                        val textWithoutIndent = text.trimStart()\n                        rawReplaceWithText(expectedIndent.spaces + textWithoutIndent)\n                    }\n                }\n\n                /*\n                 * Either this is the very first string template entry, or an\n                 * entry which immediately follows the newline.\n                 */\n                index == 0 || templateEntryFollowingNewline -> {\n                    fixFirstTemplateEntries(\n                        templateEntry,\n                        expectedIndentation = expectedIndent,\n                        actualIndentation = actualIndent)\n\n                    /*\n                     * Re-set the flag.\n                     */\n                    templateEntryFollowingNewline = false\n                }\n            }\n        }\n    }\n\n    /**\n     * Modifies [templateEntry] by correcting its indentation level.\n     *\n     * This method can be used to fix all [lines][LITERAL_STRING_TEMPLATE_ENTRY]\n     * of a [string template][STRING_TEMPLATE] except for the last one.\n     *\n     * Also, it considers `$foo` insertions in a string.\n     *\n     * @param templateEntry a [LITERAL_STRING_TEMPLATE_ENTRY] node.\n     * @param expectedIndentation the expected indentation level, as returned by\n     *   [IndentationError.expected].\n     * @param actualIndentation the actual indentation level, as returned by\n     *   [IndentationError.actual].\n     */\n    private fun fixFirstTemplateEntries(\n        templateEntry: ASTNode,\n        expectedIndentation: Int,\n        actualIndentation: Int\n    ) {\n        require(templateEntry.elementType == LITERAL_STRING_TEMPLATE_ENTRY) {\n            \"The elementType of this node is ${templateEntry.elementType} while $LITERAL_STRING_TEMPLATE_ENTRY expected\"\n        }\n\n        /*\n         * Quite possible, do nothing in this case.\n         */\n        if (expectedIndentation == actualIndentation) {\n            return\n        }\n\n        withIndentationConfig(configuration) {\n            /*\n             * A `REGULAR_STRING_PART`.\n             */\n            val regularStringPart = templateEntry.firstChildNode as LeafPsiElement\n            val regularStringPartText = regularStringPart.checkRegularStringPart().text\n            // shift of the node depending on its initial string template indentation\n            val nodeStartIndent = (regularStringPartText.leadingSpaceCount() - actualIndentation - SINGLE).zeroIfNegative()\n\n            val isPrevStringTemplate = templateEntry.treePrev.elementType in stringLiteralTokens\n            val isNextStringTemplate = templateEntry.treeNext.elementType in stringLiteralTokens\n\n            val correctedText = when {\n                isPrevStringTemplate -> when {\n                    isNextStringTemplate -> regularStringPartText\n\n                    // if string template is before literal_string\n                    else -> regularStringPartText.trimEnd()\n                }\n\n                // if string template is after literal_string\n                // or if there is no string template in literal_string\n                else -> (expectedIndentation + SINGLE + nodeStartIndent).spaces + regularStringPartText.trimStart()\n            }\n\n            regularStringPart.rawReplaceWithText(correctedText)\n        }\n    }\n\n    private fun ASTNode.getExceptionalIndentInitiator() = treeParent.let { parent ->\n        when (parent.psi) {\n            // fixme: custom logic for determining exceptional indent initiator, should be moved elsewhere\n            // get the topmost expression to keep extended indent for the whole chain of dot call expressions\n            is KtDotQualifiedExpression -> parents().takeWhile { it.elementType == DOT_QUALIFIED_EXPRESSION || it.elementType == SAFE_ACCESS_EXPRESSION }.last()\n            is KtIfExpression -> parent.findChildByType(THEN) ?: parent.findChildByType(ELSE) ?: parent\n            is KtLoopExpression -> (parent.psi as KtLoopExpression).body?.node ?: parent\n            else -> parent\n        }\n    }\n\n    /**\n     * @return the amount by which the indentation should be incremented\n     *   once this node is encountered (may be [none][NONE]).\n     * @see ASTNode.getIndentationDecrement\n     */\n    private fun ASTNode.getIndentationIncrement(): IndentationAmount =\n        when (elementType) {\n            /*\n             * A special case of an opening parenthesis which *may* or *may not*\n             * increment the indentation.\n             */\n            LPAR -> getParenthesisIndentationChange()\n\n            in increasingTokens -> SINGLE\n\n            else -> NONE\n        }\n\n    /**\n     * @return the amount by which the indentation should be decremented\n     *   once this node is encountered (may be [none][NONE]).\n     * @see ASTNode.getIndentationIncrement\n     */\n    private fun ASTNode.getIndentationDecrement(): IndentationAmount =\n        when (elementType) {\n            /*\n             * A special case of a closing parenthesis which *may* or *may not*\n             * increment the indentation.\n             */\n            RPAR -> getParenthesisIndentationChange()\n\n            in decreasingTokens -> SINGLE\n\n            else -> NONE\n        }\n\n    /**\n     * Parentheses always affect indentation when they're a part of a\n     * [VALUE_PARAMETER_LIST] (formal arguments) or a [VALUE_ARGUMENT_LIST]\n     * (effective function call arguments).\n     *\n     * When they're children of a [PARENTHESIZED] (often inside a\n     * [BINARY_EXPRESSION]), contribute to the indentation depending on\n     * whether there's a newline after the opening parenthesis.\n     *\n     * @receiver an opening or a closing parenthesis.\n     * @return the amount by which the indentation should be incremented\n     *   (after [LPAR]) or decremented (after [RPAR]). The returned value\n     *   may well be [NONE], meaning the indentation level should be\n     *   preserved.\n     * @see BINARY_EXPRESSION\n     * @see PARENTHESIZED\n     * @see VALUE_ARGUMENT_LIST\n     * @see VALUE_PARAMETER_LIST\n     */\n    private fun ASTNode.getParenthesisIndentationChange(): IndentationAmount {\n        require(elementType in arrayOf(LPAR, RPAR)) {\n            elementType.toString()\n        }\n\n        return when (treeParent.elementType) {\n            PARENTHESIZED -> when (elementType) {\n                /*\n                 * `LPAR` inside a binary expression only contributes to the\n                 * indentation if it's immediately followed by a newline.\n                 */\n                LPAR -> when {\n                    treeNext.isWhiteSpaceWithNewline() -> IndentationAmount.valueOf(configuration.extendedIndentAfterOperators)\n                    else -> NONE\n                }\n\n                /*\n                 * `RPAR` inside a binary expression affects the indentation\n                 * only if its matching `LPAR` node does so.\n                 */\n                else -> {\n                    val openingParenthesis = elementType.braceMatchOrNull()?.let { braceMatch ->\n                        treeParent.findChildByType(braceMatch)\n                    }\n                    openingParenthesis?.getParenthesisIndentationChange() ?: NONE\n                }\n            }\n\n            /*\n             * Either a control-flow statement (one of IF, WHEN, FOR or\n             * DO_WHILE), a function declaration (VALUE_PARAMETER_LIST or\n             * PROPERTY_ACCESSOR), or a function call (VALUE_ARGUMENT_LIST).\n             */\n            else -> SINGLE\n        }\n    }\n\n    /**\n     * Holds a mutable state needed to calculate the indentation and keep track\n     * of exceptions.\n     *\n     * Tokens from [increasingTokens] are stored in stack [activeTokens]. When [WHITE_SPACE] with line break is encountered,\n     * if stack is not empty, indentation is increased. When token from [decreasingTokens] is encountered, it's counterpart is removed\n     * from stack. If there has been a [WHITE_SPACE] with line break between them, indentation is decreased.\n     *\n     * @see IndentationConfigAware\n     */\n    private class IndentContext(config: IndentationConfig) : IndentationAware, IndentationConfigAware by IndentationConfigAware(config) {\n        private var regularIndent = 0\n        private val exceptionalIndents: MutableList<ExceptionalIndent> = mutableListOf()\n\n        /**\n         * The stack of element types (either [WHITE_SPACE] or any of\n         * [increasingTokens]) along with the indentation changes the\n         * corresponding elements induce.\n         *\n         * [WHITE_SPACE] is always accompanied by [no indentation change][NONE].\n         */\n        private val activeTokens: Stack<IndentedElementType> = Stack()\n\n        /**\n         * @return full current indentation.\n         */\n        @Suppress(\n            \"CUSTOM_GETTERS_SETTERS\",\n            \"WRONG_NAME_OF_VARIABLE_INSIDE_ACCESSOR\",  // #1464\n        )\n        override val indentation: Int\n            get() =\n                regularIndent + exceptionalIndents.sumOf(ExceptionalIndent::indentation)\n\n        /**\n         * Pushes [token] onto the [stack][activeTokens], but doesn't increment\n         * the indentation. The indentation is incremented separately, see\n         * [maybeIncrement].\n         *\n         * A call to this method **may or may not** be followed by a single call\n         * to [maybeIncrement].\n         *\n         * @param token a token that caused indentation increment, any of\n         *   [increasingTokens] (e.g.: an [opening brace][LPAR]).\n         * @param increment the indentation increment (must be non-zero).\n         * @see maybeIncrement\n         */\n        fun storeIncrementingToken(token: IElementType, increment: IndentationAmount) {\n            require(token in increasingTokens) {\n                \"The token is $token while any of $increasingTokens expected\"\n            }\n            require(increment.isNonZero()) {\n                \"The indentation increment is zero\"\n            }\n\n            activeTokens.push(token to increment)\n        }\n\n        /**\n         * Increments the indentation if a multi-line [WHITE_SPACE] is\n         * encountered after an opening brace.\n         *\n         * A call to this method **always** has a preceding call to\n         * [storeIncrementingToken].\n         *\n         * @see minusAssign\n         */\n        fun maybeIncrement() {\n            val headOrNull: IndentedElementType? = activeTokens.peek()\n            check(headOrNull == null ||\n                    headOrNull.type == WHITE_SPACE ||\n                    headOrNull.type in increasingTokens) {\n                \"The head of the stack is $headOrNull while only $WHITE_SPACE or any of $increasingTokens expected\"\n            }\n\n            if (headOrNull != null && headOrNull.type != WHITE_SPACE) {\n                regularIndent += headOrNull.indentationChange\n                activeTokens.push(WHITE_SPACE to NONE)\n            }\n        }\n\n        /**\n         * Pops tokens from the [stack][activeTokens] and decrements the\n         * indentation accordingly.\n         *\n         * @param token a token that caused indentation decrement, any of\n         *   [decreasingTokens] (e.g.: a [closing brace][RPAR]).\n         * @see maybeIncrement\n         */\n        operator fun minusAssign(token: IElementType) {\n            require(token in decreasingTokens) {\n                \"The token is $token while any of $decreasingTokens expected\"\n            }\n\n            if (activeTokens.peek()?.type == WHITE_SPACE) {\n                /*-\n                 * In practice, there's always only a single `WHITE_SPACE`\n                 * element type (representing the newline) pushed onto the stack\n                 * after an opening brace (`LPAR` & friends), so it needs to be\n                 * popped only once.\n                 *\n                 * Still, preserving the logic for compatibility.\n                 */\n                while (activeTokens.peek()?.type == WHITE_SPACE) {\n                    activeTokens.pop()\n                }\n\n                /*-\n                 * If an opening brace (`LPAR` etc.) was followed by a newline,\n                 * this has led to the indentation being increased.\n                 *\n                 * Now, let's decrease it back to the original value.\n                 */\n                val headOrNull: IndentedElementType? = activeTokens.peek()\n                if (headOrNull != null && headOrNull.type == token.braceMatchOrNull()) {\n                    regularIndent -= headOrNull.indentationChange\n                }\n            }\n\n            /*\n             * In practice, the predicate is always `true` (provided braces are\n             * balanced) and can be replaced with a `check()` call.\n             */\n            val headOrNull: IndentedElementType? = activeTokens.peek()\n            if (headOrNull != null && headOrNull.type == token.braceMatchOrNull()) {\n                /*\n                 * Pop the matching opening brace.\n                 */\n                activeTokens.pop()\n            }\n        }\n\n        /**\n         * @param initiator a node that caused exceptional indentation\n         * @param indentation an additional indentation.\n         * @param includeLastChild whether the last child node should be included in the range affected by exceptional indentation\n         * @return true if add exception in exceptionalIndents\n         */\n        fun addException(\n            initiator: ASTNode,\n            indentation: Int,\n            includeLastChild: Boolean\n        ) = exceptionalIndents.add(ExceptionalIndent(initiator, indentation, includeLastChild))\n\n        /**\n         * @param astNode the node which is used to determine whether exceptional indents are still active\n         * @return boolean result\n         */\n        fun checkAndReset(astNode: ASTNode) = exceptionalIndents.retainAll { it.isActive(astNode) }\n\n        /**\n         * @property initiator a node that caused exceptional indentation\n         * @property indentation an additional indentation.\n         * @property includeLastChild whether the last child node should be included in the range affected by exceptional indentation\n         */\n        private data class ExceptionalIndent(\n            val initiator: ASTNode,\n            override val indentation: Int,\n            val includeLastChild: Boolean = true\n        ) : IndentationAware {\n            /**\n             * Checks whether this exceptional indentation is still active. This is a hypotheses that exceptional indentation will end\n             * outside of node where it appeared, e.g. when an expression after assignment operator is over.\n             *\n             * @param currentNode the current node during AST traversal\n             * @return boolean result\n             */\n            fun isActive(currentNode: ASTNode): Boolean = currentNode.psi.parentsWithSelf.any { it.node == initiator } &&\n                    (includeLastChild || currentNode.treeNext != initiator.lastChildNode)\n        }\n    }\n\n    companion object {\n        private val log = KotlinLogging.logger {}\n        const val NAME_ID = \"indentation\"\n        private val increasingTokens: Set<IElementType> = linkedSetOf(LPAR, LBRACE, LBRACKET, LONG_TEMPLATE_ENTRY_START)\n        private val decreasingTokens: Set<IElementType> = linkedSetOf(RPAR, RBRACE, RBRACKET, LONG_TEMPLATE_ENTRY_END)\n\n        /**\n         * This is essentially a bi-map, which allows to look up a closing brace\n         * type by an opening brace type, or vice versa.\n         */\n        private val matchingTokens = (increasingTokens.asSequence() zip decreasingTokens.asSequence()).flatMap { (opening, closing) ->\n            sequenceOf(opening to closing, closing to opening)\n        }.toMap()\n        private val stringLiteralTokens = listOf(SHORT_STRING_TEMPLATE_ENTRY, LONG_STRING_TEMPLATE_ENTRY)\n        private val knownTrimFunctionPatterns = sequenceOf(String::trimIndent, String::trimMargin)\n            .map(KCallable<String>::name)\n            .toSet()\n\n        /**\n         * @return a string which consists of `N` [space][SPACE] characters.\n         */\n        @Suppress(\"CUSTOM_GETTERS_SETTERS\")\n        private val Int.spaces: String\n            get() =\n                SPACE.toString().repeat(n = this)\n\n        /**\n         * @return `true` if this is a [whitespace][WHITE_SPACE] node containing\n         *   a [newline][NEWLINE], `false` otherwise.\n         */\n        private fun ASTNode.isMultilineWhitespace(): Boolean =\n            elementType == WHITE_SPACE && textContains(NEWLINE)\n\n        @OptIn(ExperimentalContracts::class)\n        private fun ASTNode?.isMultilineStringTemplate(): Boolean {\n            contract {\n                returns(true) implies (this@isMultilineStringTemplate != null)\n            }\n\n            this ?: return false\n\n            return elementType == STRING_TEMPLATE &&\n                    getAllChildrenWithType(LITERAL_STRING_TEMPLATE_ENTRY).any { entry ->\n                        entry.textContains(NEWLINE)\n                    }\n        }\n\n        /**\n         * @return `true` if this is a [String.trimIndent] or [String.trimMargin]\n         * call, `false` otherwise.\n         */\n        @OptIn(ExperimentalContracts::class)\n        private fun ASTNode?.isTrimIndentOrMarginCall(): Boolean {\n            contract {\n                returns(true) implies (this@isTrimIndentOrMarginCall != null)\n            }\n\n            this ?: return false\n\n            require(elementType == CALL_EXPRESSION) {\n                \"The elementType of this node is $elementType while $CALL_EXPRESSION expected\"\n            }\n\n            val referenceExpression = firstChildNode ?: return false\n            if (referenceExpression.elementType != REFERENCE_EXPRESSION) {\n                return false\n            }\n\n            val identifier = referenceExpression.firstChildNode ?: return false\n            if (identifier.elementType != IDENTIFIER) {\n                return false\n            }\n\n            return identifier.text in knownTrimFunctionPatterns\n        }\n\n        private fun ASTNode.getNextDotExpression(): ASTNode? =\n            when (elementType) {\n                DOT_QUALIFIED_EXPRESSION -> this\n                else -> getFirstChildWithType(DOT_QUALIFIED_EXPRESSION)\n            }\n\n        /**\n         * @return the matching closing brace type for this opening brace type,\n         *   or vice versa.\n         */\n        private fun IElementType.braceMatchOrNull(): IElementType? =\n            matchingTokens[this]\n\n        /**\n         * Checks this [REGULAR_STRING_PART] child of a [LITERAL_STRING_TEMPLATE_ENTRY].\n         *\n         * @return this `REGULAR_STRING_PART` PSI element.\n         */\n        private fun LeafPsiElement.checkRegularStringPart(): LeafPsiElement {\n            val lastRegularStringPartType = elementType\n\n            check(lastRegularStringPartType == REGULAR_STRING_PART) {\n                \"Unexpected type of the 1st child of the string template entry, \" +\n                        \"expected: $REGULAR_STRING_PART, \" +\n                        \"actual: $lastRegularStringPartType, \" +\n                        \"string template: ${parent.parent.text}\"\n            }\n\n            return this\n        }\n\n        /**\n         * @return this very integer if non-negative, 0 otherwise.\n         */\n        private fun Int.zeroIfNegative(): Int =\n            when {\n                this > 0 -> this\n                else -> 0\n            }\n\n        /**\n         * Processes fragments like:\n         *\n         * ```kotlin\n         * f(\n         *     \"\"\"\n         *     |foobar\n         *     \"\"\".trimMargin()\n         * )\n         * ```\n         *\n         * @param whitespace the whitespace node between an [LPAR] and the\n         *   `trimIndent()`- or `trimMargin()`- terminated string template, which is\n         *   an effective argument of a function call. The string template is\n         *   expected to begin on a separate line (otherwise, there'll be no\n         *   whitespace in-between).\n         * @return `true` if the opening and the closing quotes of the string\n         *   template are aligned, `false` otherwise.\n         */\n        private fun hasAlignedOpeningAndClosingQuotes(whitespace: ASTNode, expectedIndent: Int): Boolean {\n            require(whitespace.isMultilineWhitespace()) {\n                \"The node is $whitespace while a multi-line $WHITE_SPACE expected\"\n            }\n\n            /*\n             * Here, we expect that `nextNode` is a VALUE_ARGUMENT which contains\n             * the dot-qualified expression (`STRING_TEMPLATE.trimIndent()` or\n             * `STRING_TEMPLATE.trimMargin()`).\n             */\n            val nextFunctionArgument = whitespace.treeNext\n            if (nextFunctionArgument.elementType == VALUE_ARGUMENT) {\n                val memberOrExtensionCall = nextFunctionArgument.getNextDotExpression()\n\n                /*\n                 * Limit allowed member or extension calls to `trimIndent()` and\n                 * `trimMargin()`.\n                 */\n                if (memberOrExtensionCall != null &&\n                        memberOrExtensionCall.getFirstChildWithType(CALL_EXPRESSION).isTrimIndentOrMarginCall()) {\n                    val stringTemplate = memberOrExtensionCall.getFirstChildWithType(STRING_TEMPLATE)\n\n                    /*\n                     * Limit the logic to multi-line string templates only (the\n                     * opening and closing quotes of a single-line template are,\n                     * obviously, always mis-aligned).\n                     */\n                    if (stringTemplate != null && stringTemplate.isMultilineStringTemplate()) {\n                        val closingQuoteIndent = stringTemplate.getFirstChildWithType(CLOSING_QUOTE)\n                            ?.treePrev\n                            ?.text\n                            ?.length ?: -1\n                        return expectedIndent == closingQuoteIndent\n                    }\n                }\n            }\n\n            return true\n        }\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/main/kotlin/com/saveourtool/diktat/ruleset/rules/chapter3/files/IndentedElementType.kt",
    "content": "@file:Suppress(\"HEADER_MISSING_IN_NON_SINGLE_CLASS_FILE\")\n\npackage com.saveourtool.diktat.ruleset.rules.chapter3.files\n\nimport org.jetbrains.kotlin.com.intellij.psi.tree.IElementType\n\n/**\n * @return the element type.\n */\n@Suppress(\"CUSTOM_GETTERS_SETTERS\")\ninternal val IndentedElementType.type: IElementType\n    get() =\n        first\n\n/**\n * @return the indentation change.\n */\n@Suppress(\"CUSTOM_GETTERS_SETTERS\")\ninternal val IndentedElementType.indentationChange: IndentationAmount\n    get() =\n        second\n\n/**\n * An [IElementType] along with the indentation change it induces.\n */\ninternal typealias IndentedElementType = Pair<IElementType, IndentationAmount>\n"
  },
  {
    "path": "diktat-rules/src/main/kotlin/com/saveourtool/diktat/ruleset/rules/chapter3/files/NewlinesRule.kt",
    "content": "package com.saveourtool.diktat.ruleset.rules.chapter3.files\n\nimport com.saveourtool.diktat.common.config.rules.RuleConfiguration\nimport com.saveourtool.diktat.common.config.rules.RulesConfig\nimport com.saveourtool.diktat.common.config.rules.getRuleConfig\nimport com.saveourtool.diktat.ruleset.constants.Warnings.COMPLEX_EXPRESSION\nimport com.saveourtool.diktat.ruleset.constants.Warnings.WRONG_NEWLINES\nimport com.saveourtool.diktat.ruleset.rules.DiktatRule\nimport com.saveourtool.diktat.ruleset.utils.appendNewlineMergingWhiteSpace\nimport com.saveourtool.diktat.ruleset.utils.changeWhiteSpaceOnNewline\nimport com.saveourtool.diktat.ruleset.utils.emptyBlockList\nimport com.saveourtool.diktat.ruleset.utils.findAllDescendantsWithSpecificType\nimport com.saveourtool.diktat.ruleset.utils.findAllNodesWithCondition\nimport com.saveourtool.diktat.ruleset.utils.findParentNodeWithSpecificType\nimport com.saveourtool.diktat.ruleset.utils.getAllChildrenWithType\nimport com.saveourtool.diktat.ruleset.utils.getFilePath\nimport com.saveourtool.diktat.ruleset.utils.getFirstChildWithType\nimport com.saveourtool.diktat.ruleset.utils.getIdentifierName\nimport com.saveourtool.diktat.ruleset.utils.getRootNode\nimport com.saveourtool.diktat.ruleset.utils.hasParent\nimport com.saveourtool.diktat.ruleset.utils.isBeginByNewline\nimport com.saveourtool.diktat.ruleset.utils.isFollowedByNewline\nimport com.saveourtool.diktat.ruleset.utils.isGradleScript\nimport com.saveourtool.diktat.ruleset.utils.isSingleLineIfElse\nimport com.saveourtool.diktat.ruleset.utils.isWhiteSpaceWithNewline\nimport com.saveourtool.diktat.ruleset.utils.leaveOnlyOneNewLine\nimport com.saveourtool.diktat.ruleset.utils.nextCodeSibling\nimport com.saveourtool.diktat.ruleset.utils.parent\nimport com.saveourtool.diktat.ruleset.utils.prevCodeSibling\n\nimport io.github.oshai.kotlinlogging.KotlinLogging\nimport org.jetbrains.kotlin.KtNodeTypes.BINARY_EXPRESSION\nimport org.jetbrains.kotlin.KtNodeTypes.BLOCK\nimport org.jetbrains.kotlin.KtNodeTypes.CALLABLE_REFERENCE_EXPRESSION\nimport org.jetbrains.kotlin.KtNodeTypes.CALL_EXPRESSION\nimport org.jetbrains.kotlin.KtNodeTypes.CLASS\nimport org.jetbrains.kotlin.KtNodeTypes.CONDITION\nimport org.jetbrains.kotlin.KtNodeTypes.DOT_QUALIFIED_EXPRESSION\nimport org.jetbrains.kotlin.KtNodeTypes.FUN\nimport org.jetbrains.kotlin.KtNodeTypes.FUNCTION_LITERAL\nimport org.jetbrains.kotlin.KtNodeTypes.FUNCTION_TYPE\nimport org.jetbrains.kotlin.KtNodeTypes.FUNCTION_TYPE_RECEIVER\nimport org.jetbrains.kotlin.KtNodeTypes.IF\nimport org.jetbrains.kotlin.KtNodeTypes.IMPORT_DIRECTIVE\nimport org.jetbrains.kotlin.KtNodeTypes.LAMBDA_ARGUMENT\nimport org.jetbrains.kotlin.KtNodeTypes.OPERATION_REFERENCE\nimport org.jetbrains.kotlin.KtNodeTypes.PACKAGE_DIRECTIVE\nimport org.jetbrains.kotlin.KtNodeTypes.POSTFIX_EXPRESSION\nimport org.jetbrains.kotlin.KtNodeTypes.PRIMARY_CONSTRUCTOR\nimport org.jetbrains.kotlin.KtNodeTypes.REFERENCE_EXPRESSION\nimport org.jetbrains.kotlin.KtNodeTypes.RETURN\nimport org.jetbrains.kotlin.KtNodeTypes.SAFE_ACCESS_EXPRESSION\nimport org.jetbrains.kotlin.KtNodeTypes.SECONDARY_CONSTRUCTOR\nimport org.jetbrains.kotlin.KtNodeTypes.SUPER_TYPE_CALL_ENTRY\nimport org.jetbrains.kotlin.KtNodeTypes.SUPER_TYPE_ENTRY\nimport org.jetbrains.kotlin.KtNodeTypes.SUPER_TYPE_LIST\nimport org.jetbrains.kotlin.KtNodeTypes.VALUE_ARGUMENT\nimport org.jetbrains.kotlin.KtNodeTypes.VALUE_ARGUMENT_LIST\nimport org.jetbrains.kotlin.KtNodeTypes.VALUE_PARAMETER\nimport org.jetbrains.kotlin.KtNodeTypes.VALUE_PARAMETER_LIST\nimport org.jetbrains.kotlin.KtNodeTypes.WHEN\nimport org.jetbrains.kotlin.com.intellij.lang.ASTNode\nimport org.jetbrains.kotlin.com.intellij.psi.PsiElement\nimport org.jetbrains.kotlin.com.intellij.psi.impl.source.tree.LeafPsiElement\nimport org.jetbrains.kotlin.com.intellij.psi.impl.source.tree.PsiWhiteSpaceImpl\nimport org.jetbrains.kotlin.com.intellij.psi.tree.IElementType\nimport org.jetbrains.kotlin.com.intellij.psi.tree.TokenSet\nimport org.jetbrains.kotlin.kdoc.lexer.KDocTokens.KDOC\nimport org.jetbrains.kotlin.lexer.KtTokens.ANDAND\nimport org.jetbrains.kotlin.lexer.KtTokens.ARROW\nimport org.jetbrains.kotlin.lexer.KtTokens.BLOCK_COMMENT\nimport org.jetbrains.kotlin.lexer.KtTokens.COLON\nimport org.jetbrains.kotlin.lexer.KtTokens.COLONCOLON\nimport org.jetbrains.kotlin.lexer.KtTokens.COMMA\nimport org.jetbrains.kotlin.lexer.KtTokens.DIV\nimport org.jetbrains.kotlin.lexer.KtTokens.DIVEQ\nimport org.jetbrains.kotlin.lexer.KtTokens.DOT\nimport org.jetbrains.kotlin.lexer.KtTokens.ELVIS\nimport org.jetbrains.kotlin.lexer.KtTokens.EOL_COMMENT\nimport org.jetbrains.kotlin.lexer.KtTokens.EQ\nimport org.jetbrains.kotlin.lexer.KtTokens.IDENTIFIER\nimport org.jetbrains.kotlin.lexer.KtTokens.LPAR\nimport org.jetbrains.kotlin.lexer.KtTokens.MINUS\nimport org.jetbrains.kotlin.lexer.KtTokens.MINUSEQ\nimport org.jetbrains.kotlin.lexer.KtTokens.MUL\nimport org.jetbrains.kotlin.lexer.KtTokens.MULTEQ\nimport org.jetbrains.kotlin.lexer.KtTokens.OROR\nimport org.jetbrains.kotlin.lexer.KtTokens.PLUS\nimport org.jetbrains.kotlin.lexer.KtTokens.PLUSEQ\nimport org.jetbrains.kotlin.lexer.KtTokens.RETURN_KEYWORD\nimport org.jetbrains.kotlin.lexer.KtTokens.RPAR\nimport org.jetbrains.kotlin.lexer.KtTokens.SAFE_ACCESS\nimport org.jetbrains.kotlin.lexer.KtTokens.WHITE_SPACE\nimport org.jetbrains.kotlin.psi.KtBinaryExpression\nimport org.jetbrains.kotlin.psi.KtNamedFunction\nimport org.jetbrains.kotlin.psi.KtParameterList\nimport org.jetbrains.kotlin.psi.KtReferenceExpression\nimport org.jetbrains.kotlin.psi.KtSuperTypeList\nimport org.jetbrains.kotlin.psi.KtValueArgumentList\nimport org.jetbrains.kotlin.psi.psiUtil.anyDescendantOfType\nimport org.jetbrains.kotlin.psi.psiUtil.children\nimport org.jetbrains.kotlin.psi.psiUtil.parents\nimport org.jetbrains.kotlin.psi.psiUtil.siblings\n\nprivate typealias ListOfList = MutableList<MutableList<ASTNode>>\n\n/**\n * Rule that checks line break styles:\n * 1. Checks that some operators are followed by newline, while others are prepended by it\n * 2. Statements that follow `!!` behave in the same way\n * 3. Forces functional style of chained dot call expressions with exception\n * 4. Checks that newline is placed after assignment operator, not before\n * 5. Ensures that function or constructor name isn't separated from `(` by space or newline\n * 6. Ensures that in multiline lambda newline follows arrow or, in case of lambda without explicit parameters, opening brace\n * 7. Checks that functions with single `return` are simplified to functions with expression body\n * 8. Parameter or argument lists and supertype lists that have more than 2 elements should be separated by newlines\n * 9. Complex expression inside condition replaced with new variable\n */\n@Suppress(\"ForbiddenComment\")\nclass NewlinesRule(configRules: List<RulesConfig>) : DiktatRule(\n    NAME_ID,\n    configRules,\n    listOf(COMPLEX_EXPRESSION, WRONG_NEWLINES)\n) {\n    private val configuration by lazy {\n        NewlinesRuleConfiguration(configRules.getRuleConfig(WRONG_NEWLINES)?.configuration ?: emptyMap())\n    }\n\n    override fun logic(node: ASTNode) {\n        when (node.elementType) {\n            OPERATION_REFERENCE, EQ -> handleOperatorWithLineBreakAfter(node)\n            // this logic regulates indentation with elements - so that the symbol and the subsequent expression are on the same line\n            in lineBreakBeforeOperators -> handleOperatorWithLineBreakBefore(node)\n            LPAR -> handleOpeningParentheses(node)\n            COMMA -> handleComma(node)\n            COLON -> handleColon(node)\n            BLOCK -> handleLambdaBody(node)\n            RETURN -> handleReturnStatement(node)\n            SUPER_TYPE_LIST, VALUE_PARAMETER_LIST, VALUE_ARGUMENT_LIST -> handleList(node)\n            // this logic splits long expressions into multiple lines\n            DOT_QUALIFIED_EXPRESSION, SAFE_ACCESS_EXPRESSION, POSTFIX_EXPRESSION -> handDotQualifiedAndSafeAccessExpression(node)\n            else -> {\n            }\n        }\n    }\n\n    @Suppress(\"GENERIC_VARIABLE_WRONG_DECLARATION\", \"MagicNumber\")\n    private fun handDotQualifiedAndSafeAccessExpression(node: ASTNode) {\n        val listParentTypesNoFix = listOf(PACKAGE_DIRECTIVE, IMPORT_DIRECTIVE, VALUE_PARAMETER_LIST,\n            VALUE_ARGUMENT_LIST, DOT_QUALIFIED_EXPRESSION, SAFE_ACCESS_EXPRESSION, POSTFIX_EXPRESSION)\n        if (isNotFindParentNodeWithSpecificManyType(node, listParentTypesNoFix)) {\n            val listDot = node.findAllNodesWithCondition(\n                withSelf = true,\n                excludeChildrenCondition = { !isDotQuaOrSafeAccessOrPostfixExpression(it) }\n            ) {\n                isDotQuaOrSafeAccessOrPostfixExpression(it) && it.elementType != POSTFIX_EXPRESSION\n            }.reversed()\n            if (listDot.size > configuration.maxCallsInOneLine) {\n                val without = listDot.filterIndexed { index, it ->\n                    val nodeBeforeDotOrSafeAccess = it.findChildByType(DOT)?.treePrev ?: it.findChildByType(SAFE_ACCESS)?.treePrev\n                    val firstElem = it.firstChildNode\n                    val isTextContainsParenthesized = isTextContainsFunctionCall(firstElem)\n                    val isNotWhiteSpaceBeforeDotOrSafeAccessContainNewLine = nodeBeforeDotOrSafeAccess?.elementType != WHITE_SPACE ||\n                            nodeBeforeDotOrSafeAccess?.let { it.elementType == WHITE_SPACE || it.textContains('\\n') } == false\n                    isTextContainsParenthesized && (index > 0) && isNotWhiteSpaceBeforeDotOrSafeAccessContainNewLine\n                }\n                if (without.isNotEmpty()) {\n                    WRONG_NEWLINES.warnAndFix(configRules, emitWarn, isFixMode, \"wrong split long `dot qualified expression` or `safe access expression`\",\n                        node.startOffset, node) {\n                        fixDotQualifiedExpression(without)\n                    }\n                }\n            }\n        }\n    }\n\n    /**\n     * Return false, if you find parent with types in list else return true\n     */\n    private fun isNotFindParentNodeWithSpecificManyType(node: ASTNode, list: List<IElementType>): Boolean {\n        list.forEach { elem ->\n            node.findParentNodeWithSpecificType(elem)?.let {\n                return false\n            }\n        }\n        return true\n    }\n\n    /**\n     * Fix Dot Qualified Expression and Safe Access Expression -\n     * 1) Append new White Space node before second and subsequent node Dot or Safe Access\n     * in Dot Qualified Expression? Safe Access Expression and Postfix Expression\n     * 2) If before first Dot or Safe Access node stay White Space node with \\n - remove this node\n     */\n    private fun fixDotQualifiedExpression(list: List<ASTNode>) {\n        list.forEach { astNode ->\n            val dotNode = astNode.getFirstChildWithType(DOT) ?: astNode.getFirstChildWithType(SAFE_ACCESS)\n            val nodeBeforeDot = dotNode?.treePrev\n            astNode.appendNewlineMergingWhiteSpace(nodeBeforeDot, dotNode)\n        }\n    }\n\n    private fun isDotQuaOrSafeAccessOrPostfixExpression(node: ASTNode) =\n        node.elementType == DOT_QUALIFIED_EXPRESSION || node.elementType == SAFE_ACCESS_EXPRESSION || node.elementType == POSTFIX_EXPRESSION\n\n    private fun handleOperatorWithLineBreakAfter(node: ASTNode) {\n        // [node] should be either EQ or OPERATION_REFERENCE which has single child\n        if (node.elementType != EQ && node.firstChildNode.elementType !in lineBreakAfterOperators && !node.isInfixCall()) {\n            return\n        }\n\n        // We need to check newline only if prevCodeSibling exists. It can be not the case for unary operators, which are placed\n        // at the beginning of the line.\n        if (node.prevCodeSibling()?.isFollowedByNewline() == true) {\n            WRONG_NEWLINES.warnAndFix(configRules, emitWarn, isFixMode,\n                \"should break a line after and not before ${node.text}\", node.startOffset, node) {\n                node.run {\n                    treeParent.removeChild(treePrev)\n                    if (!isFollowedByNewline()) {\n                        treeParent.appendNewlineMergingWhiteSpace(treeNext.takeIf { it.elementType == WHITE_SPACE }, treeNext)\n                    }\n                }\n            }\n        }\n    }\n\n    @Suppress(\"ComplexMethod\", \"TOO_LONG_FUNCTION\")\n    private fun handleOperatorWithLineBreakBefore(node: ASTNode) {\n        if (node.isDotFromPackageOrImport()) {\n            return\n        }\n        val isIncorrect = (if (node.elementType == ELVIS) node.treeParent else node).run {\n            if (isInvalidCallsChain(dropLeadingProperties = true)) {\n                if (node.isInParentheses()) {\n                    checkForComplexExpression(node)\n                }\n                val isSingleLineIfElse = parent(true) { it.elementType == IF }?.isSingleLineIfElse() ?: false\n                // to follow functional style these operators should be started by newline\n                (isFollowedByNewline() || !isBeginByNewline()) && !isSingleLineIfElse &&\n                        (!isFirstCall() || !isMultilineLambda(treeParent))\n            } else {\n                if (isInvalidCallsChain(dropLeadingProperties = false) && node.isInParentheses()) {\n                    checkForComplexExpression(node)\n                }\n                // unless statement is simple and on single line, these operators cannot have newline after\n                isFollowedByNewline() && !isSingleDotStatementOnSingleLine()\n            }\n        }\n        if (isIncorrect || node.isElvisCorrect()) {\n            val freeText = if (node.isInvalidCallsChain() || node.isElvisCorrect()) {\n                \"should follow functional style at ${node.text}\"\n            } else {\n                \"should break a line before and not after ${node.text}\"\n            }\n            WRONG_NEWLINES.warnAndFix(configRules, emitWarn, isFixMode, freeText, node.startOffset, node) {\n                node.selfOrOperationReferenceParent().run {\n                    if (!isBeginByNewline()) {\n                        // prepend newline\n                        treeParent.appendNewlineMergingWhiteSpace(treePrev.takeIf { it.elementType == WHITE_SPACE }, this)\n                    }\n                    if (isFollowedByNewline()) {\n                        // remove newline after\n                        parent(false) { it.treeNext != null }?.let {\n                            it.treeParent.removeChild(it.treeNext)\n                        }\n                    }\n                }\n            }\n        }\n    }\n\n    private fun checkForComplexExpression(node: ASTNode) {\n        if (node.getRootNode().getFilePath().isGradleScript()) {\n            // this inspection is softened for gradle scripts, see https://github.com/saveourtool/diktat/issues/1148\n            return\n        }\n        COMPLEX_EXPRESSION.warn(configRules, emitWarn, node.text, node.startOffset, node)\n    }\n\n    private fun handleOpeningParentheses(node: ASTNode) {\n        val parent = node.treeParent\n        if (parent.elementType in listOf(VALUE_ARGUMENT_LIST, VALUE_PARAMETER_LIST)) {\n            val prevWhiteSpace = node\n                .parent(false) { it.treePrev != null }\n                ?.treePrev\n                ?.takeIf { it.elementType == WHITE_SPACE }\n            val isNotAnonymous = parent.treeParent.elementType in listOf(CALL_EXPRESSION, PRIMARY_CONSTRUCTOR, SECONDARY_CONSTRUCTOR, FUN)\n            if (prevWhiteSpace != null && isNotAnonymous) {\n                WRONG_NEWLINES.warnAndFix(configRules, emitWarn, isFixMode,\n                    \"opening parentheses should not be separated from constructor or function name\", node.startOffset, node) {\n                    prevWhiteSpace.treeParent.removeChild(prevWhiteSpace)\n                }\n            }\n        }\n    }\n\n    /**\n     * Check that newline is not placed before a comma\n     */\n    private fun handleComma(node: ASTNode) {\n        val prevNewLine = node\n            .parent(false) { it.treePrev != null }\n            ?.treePrev\n            ?.takeIf {\n                it.elementType == WHITE_SPACE && it.text.contains(\"\\n\")\n            }\n        prevNewLine?.let {\n            WRONG_NEWLINES.warnAndFix(configRules, emitWarn, isFixMode, \"newline should be placed only after comma\", node.startOffset, node) {\n                it.treeParent.removeChild(it)\n            }\n        }\n    }\n\n    /**\n     * Check that newline is not placed before or after a colon\n     */\n    private fun handleColon(node: ASTNode) {\n        val prevNewLine = node\n            .parent(false) { it.treePrev != null }\n            ?.treePrev\n            ?.takeIf {\n                it.elementType == WHITE_SPACE && it.text.contains(\"\\n\")\n            }\n        prevNewLine?.let { whiteSpace ->\n            WRONG_NEWLINES.warnAndFix(configRules, emitWarn, isFixMode, \"newline shouldn't be placed before colon\", node.startOffset, node) {\n                whiteSpace.treeParent.removeChild(whiteSpace)\n\n                if (node.hasParent(VALUE_PARAMETER_LIST)) {\n                    // If inside the list of arguments the rule for a new line before the colon has worked,\n                    // then we delete the new line on both sides of the colon\n                    whiteSpace.treeParent?.let {\n                        val nextNewLine = node\n                            .parent(false) { it.treeNext != null }\n                            ?.treeNext\n                            ?.takeIf {\n                                it.elementType == WHITE_SPACE && it.text.contains(\"\\n\")\n                            }\n                        nextNewLine?.let {\n                            it.treeParent.addChild(PsiWhiteSpaceImpl(\" \"), it)\n                            it.treeParent.removeChild(it)\n                        }\n                    }\n                }\n            }\n        }\n    }\n\n    @Suppress(\"TOO_LONG_FUNCTION\")\n    private fun handleLambdaBody(node: ASTNode) {\n        if (node.treeParent.elementType == FUNCTION_LITERAL) {\n            val isSingleLineLambda = node.treeParent\n                .text\n                .lines()\n                .size == 1\n            val arrowNode = node.siblings(false).find { it.elementType == ARROW }\n            if (!isSingleLineLambda && arrowNode != null) {\n                // lambda with explicit arguments\n                val newlinesBeforeArrow = arrowNode\n                    .siblings(false)\n                    .filter { it.isNewLineNode() }\n                    .toList()\n                if (newlinesBeforeArrow.isNotEmpty() || !arrowNode.isFollowedByNewline()) {\n                    WRONG_NEWLINES.warnAndFix(configRules, emitWarn, isFixMode,\n                        \"in lambda with several lines in body newline should be placed after an arrow\", arrowNode.startOffset, arrowNode) {\n                        // fixme: replacement logic can be sophisticated for better appearance?\n                        newlinesBeforeArrow.forEach { it.treeParent.replaceChild(it, PsiWhiteSpaceImpl(\" \")) }\n                        arrowNode.treeNext.takeIf { it.elementType == WHITE_SPACE }?.leaveOnlyOneNewLine()\n                    }\n                }\n            } else if (!isSingleLineLambda && arrowNode == null) {\n                // lambda without arguments\n                val lbraceNode = node.treeParent.firstChildNode\n                if (!lbraceNode.isFollowedByNewline()) {\n                    WRONG_NEWLINES.warnAndFix(configRules, emitWarn, isFixMode,\n                        \"in lambda with several lines in body newline should be placed after an opening brace\", lbraceNode.startOffset, lbraceNode) {\n                        lbraceNode.treeNext.let {\n                            if (it.elementType == WHITE_SPACE) {\n                                it.leaveOnlyOneNewLine()\n                            } else {\n                                it.treeParent.addChild(PsiWhiteSpaceImpl(\"\\n\"), it)\n                            }\n                        }\n                    }\n                }\n            }\n        }\n    }\n\n    @Suppress(\"UnsafeCallOnNullableType\", \"AVOID_NULL_CHECKS\")\n    private fun handleReturnStatement(node: ASTNode) {\n        val blockNode = node.treeParent.takeIf { it.elementType == BLOCK && it.treeParent.elementType == FUN }\n        val returnsUnit = node.children().count() == 1  // the only child is RETURN_KEYWORD\n        val hasMultipleReturn = node.findAllDescendantsWithSpecificType(RETURN_KEYWORD).count() > 1\n        if (blockNode == null || returnsUnit || hasMultipleReturn) {\n            // function is either already with expression body or definitely can't be converted to it\n            // or the function has more than one keyword `return` inside it\n            return\n        }\n        blockNode\n            .children()\n            .filterNot { it.elementType in emptyBlockList }\n            .toList()\n            .takeIf { it.size == 1 }\n            ?.also {\n                WRONG_NEWLINES.warnAndFix(configRules, emitWarn, isFixMode,\n                    \"functions with single return statement should be simplified to expression body\", node.startOffset, node) {\n                    val funNode = blockNode.treeParent\n                    val returnType = (funNode.psi as? KtNamedFunction)?.typeReference?.node\n                    val expression = node.findChildByType(RETURN_KEYWORD)!!.nextCodeSibling()!!\n                    val childBlockNode = funNode.findChildByType(BLOCK)\n                    funNode.apply {\n                        if (returnType != null) {\n                            removeRange(returnType.treeNext, null)\n                            addChild(PsiWhiteSpaceImpl(\" \"), null)\n                        } else if (childBlockNode != null) {\n                            removeChild(childBlockNode)\n                        }\n                        addChild(LeafPsiElement(EQ, \"=\"), null)\n                        addChild(PsiWhiteSpaceImpl(\" \"), null)\n                        addChild(expression.clone() as ASTNode, null)\n                    }\n                }\n            }\n    }\n\n    /**\n     * Checks that members of [VALUE_PARAMETER_LIST] (list of function parameters at declaration site) are separated with newlines.\n     * Also checks that entries of [SUPER_TYPE_LIST] are separated by newlines.\n     */\n    @Suppress(\"ComplexMethod\")\n    private fun handleList(node: ASTNode) {\n        if (node.elementType == VALUE_PARAMETER_LIST) {\n            // do not check list parameter in lambda\n            node.findParentNodeWithSpecificType(LAMBDA_ARGUMENT)?.let {\n                return\n            }\n            // do not check other value lists\n            if (node.treeParent.elementType.let { it == FUNCTION_TYPE || it == FUNCTION_TYPE_RECEIVER }) {\n                return\n            }\n        }\n\n        if (node.elementType == VALUE_ARGUMENT_LIST && node.siblings(forward = false).any { it.elementType == REFERENCE_EXPRESSION }) {\n            // check that it is not function invocation, but only supertype constructor calls\n            return\n        }\n\n        val (numEntries, entryType) = when (node.elementType) {\n            VALUE_PARAMETER_LIST -> (node.psi as KtParameterList).parameters.size to \"value parameters\"\n            SUPER_TYPE_LIST -> (node.psi as KtSuperTypeList).entries.size to \"supertype list entries\"\n            VALUE_ARGUMENT_LIST -> (node.psi as KtValueArgumentList).arguments.size to \"value arguments\"\n            else -> {\n                log.warn { \"Unexpected node element type ${node.elementType}\" }\n                return\n            }\n        }\n        if (numEntries > configuration.maxParametersInOneLine) {\n            when (node.elementType) {\n                VALUE_PARAMETER_LIST -> handleFirstValue(node, VALUE_PARAMETER, \"first parameter should be placed on a separate line \" +\n                        \"or all other parameters should be aligned with it in declaration of <${node.getParentIdentifier()}>\")\n                VALUE_ARGUMENT_LIST -> handleFirstValue(node, VALUE_ARGUMENT, \"first value argument (%s) should be placed on the new line \" +\n                        \"or all other parameters should be aligned with it\")\n                else -> {\n                }\n            }\n\n            handleValueParameterList(node, entryType)\n        }\n    }\n\n    private fun handleFirstValue(node: ASTNode,\n                                 filterType: IElementType,\n                                 warnText: String\n    ) = node\n        .children()\n        .takeWhile { !it.textContains('\\n') }\n        .filter { it.elementType == filterType }\n        .toList()\n        .takeIf { it.size > 1 }\n        ?.let { list ->\n            val freeText = if (filterType == VALUE_ARGUMENT) {\n                warnText.format(list.first().text)\n            } else {\n                warnText\n            }\n            WRONG_NEWLINES.warnAndFix(configRules, emitWarn, isFixMode, freeText, node.startOffset, node) {\n                list.first().treePrev?.let {\n                    node.appendNewlineMergingWhiteSpace(\n                        list.first()\n                            .treePrev\n                            .takeIf { it.elementType == WHITE_SPACE },\n                        list.first()\n                    )\n                }\n            }\n        }\n\n    /**\n     * Check that super classes are on separate lines (if there are three or more)\n     *\n     * @return true if there are less than three super classes or if all of them are on separate lines\n     */\n    private fun isCorrectSuperTypeList(valueParameterList: List<ASTNode>): Boolean {\n        val superTypeList = valueParameterList.filter { it.elementType in listOf(SUPER_TYPE_CALL_ENTRY, SUPER_TYPE_ENTRY) }\n        if (superTypeList.size <= 2) {\n            return true\n        }\n\n        val classDefinitionNode = valueParameterList[0].treeParent?.treeParent\n        val colonNodes = classDefinitionNode?.getAllChildrenWithType(COLON)\n        val newlineBeforeSuperTypeList = colonNodes?.find {colonNode ->\n            val newlineNode = colonNode.treeNext\n            val superClassType = newlineNode?.treeNext\n            newlineNode?.text?.count { it == '\\n' } == 1 && superClassType?.elementType == SUPER_TYPE_LIST\n        }\n\n        // list elements are correct if they are sequence of (COMMA, '\\n', supertype)\n        var areElementsCorrect = true\n        var valueParameter = valueParameterList[0].treeNext\n        while (valueParameter != null) {\n            val newlineNode = valueParameter.treeNext\n            val superClassType = valueParameter.treeNext?.treeNext\n            if (valueParameter.elementType != COMMA || newlineNode?.text?.count { it == '\\n' } != 1 ||\n                    superClassType?.elementType != SUPER_TYPE_ENTRY) {\n                areElementsCorrect = false\n                break\n            }\n            valueParameter = superClassType?.treeNext\n        }\n        return newlineBeforeSuperTypeList != null && areElementsCorrect\n    }\n\n    private fun setSuperClassesOnSeparateLines(\n        node: ASTNode,\n        valueParameterList: List<ASTNode>,\n        warnText: String,\n        colonNodes: List<ASTNode>?\n    ) {\n        WRONG_NEWLINES.warnAndFix(\n            configRules, emitWarn, isFixMode,\n            warnText, node.startOffset, node\n        ) {\n            valueParameterList.forEach { superClassNode ->\n                val commaNode = superClassNode.treeNext\n                val whiteSpaceNode = commaNode?.treeNext\n                // put super classes on separate lines\n                if (superClassNode.elementType in listOf(SUPER_TYPE_CALL_ENTRY, SUPER_TYPE_ENTRY) &&\n                        commaNode?.text == \",\" && whiteSpaceNode?.elementType == WHITE_SPACE\n                ) {\n                    commaNode.changeWhiteSpaceOnNewline(whiteSpaceNode, commaNode)\n                }\n\n                // add newline before the first element of super class list\n                val colonNodeBeforeList = colonNodes?.find { colonNode ->\n                    colonNode.treeNext.text.count { it == '\\n' } == 0 &&\n                            colonNode.treeNext.treeNext.elementType == SUPER_TYPE_LIST\n                }\n                colonNodeBeforeList?.changeWhiteSpaceOnNewline(colonNodeBeforeList.treeNext, colonNodeBeforeList)\n            }\n        }\n    }\n\n    private fun fixInvalidCommas(node: ASTNode, warnText: String) {\n        node.children()\n            .filter {\n                val isNewLineNext = it.treeNext?.isNewLineNode() ?: false\n                val isNewLinePrev = it.treePrev?.isNewLineNode() ?: false\n\n                (it.elementType == COMMA && !isNewLineNext) ||\n                        // Move RPAR to the new line\n                        (it.elementType == RPAR && it.treePrev?.elementType != COMMA && !isNewLinePrev)\n            }\n            .toList()\n            .takeIf { it.isNotEmpty() }\n            ?.let { invalidCommas ->\n                WRONG_NEWLINES.warnAndFix(\n                    configRules, emitWarn, isFixMode,\n                    warnText, node.startOffset, node\n                ) {\n                    invalidCommas.forEach { commaOrRpar ->\n                        val nextWhiteSpace = commaOrRpar.treeNext?.takeIf { it.elementType == WHITE_SPACE }\n                        if (commaOrRpar.elementType == COMMA) {\n                            nextWhiteSpace?.treeNext?.let {\n                                commaOrRpar.appendNewlineMergingWhiteSpace(nextWhiteSpace, nextWhiteSpace.treeNext)\n                            } ?: commaOrRpar.treeNext?.treeParent?.appendNewlineMergingWhiteSpace(nextWhiteSpace, commaOrRpar.treeNext)\n                        } else {\n                            commaOrRpar.treeParent?.appendNewlineMergingWhiteSpace(nextWhiteSpace, commaOrRpar)\n                        }\n                    }\n                }\n            }\n    }\n\n    private fun handleValueParameterList(node: ASTNode, entryType: String) {\n        val valueParameterList = node.children().toList()\n        val warnText = node.getParentIdentifier()?.let {\n            \"$entryType should be placed on different lines in declaration of <${node.getParentIdentifier()}>\"\n        } ?: \"$entryType should be placed on different lines\"\n        val classDefinitionNode = valueParameterList[0].treeParent?.treeParent\n        val colonNodes = classDefinitionNode?.getAllChildrenWithType(COLON)\n\n        if (!isCorrectSuperTypeList(valueParameterList)) {\n            setSuperClassesOnSeparateLines(node, valueParameterList, warnText, colonNodes)\n        } else {\n            fixInvalidCommas(node, warnText)\n        }\n    }\n\n    private fun ASTNode.isNewLineNode(): Boolean = this.run { elementType == WHITE_SPACE && textContains('\\n') }\n\n    @Suppress(\"UnsafeCallOnNullableType\")\n    private fun ASTNode.getParentIdentifier() = when (treeParent.elementType) {\n        PRIMARY_CONSTRUCTOR -> treeParent.treeParent\n        SECONDARY_CONSTRUCTOR -> parent(CLASS)!!\n        else -> treeParent\n    }\n        .getIdentifierName()?.text\n\n    private fun ASTNode.getOrderedCallExpressions(psi: PsiElement, result: MutableList<ASTNode>) {\n        // if statements here have the only right order - don't change it\n\n        if (psi.children.isNotEmpty() && !psi.isFirstChildElementType(DOT_QUALIFIED_EXPRESSION) &&\n                !psi.isFirstChildElementType(SAFE_ACCESS_EXPRESSION)) {\n            val firstChild = psi.firstChild\n            if (firstChild.isFirstChildElementType(DOT_QUALIFIED_EXPRESSION) ||\n                    firstChild.isFirstChildElementType(SAFE_ACCESS_EXPRESSION)) {\n                getOrderedCallExpressions(firstChild.firstChild, result)\n            }\n            result.add(firstChild.node\n                .siblings(true)\n                .dropWhile { it.elementType in dropChainValues }\n                .first()  // node treeNext is \".\", \"?.\", \"!!\", \"::\"\n            )\n        } else if (psi.children.isNotEmpty()) {\n            getOrderedCallExpressions(psi.firstChild, result)\n\n            result.add(psi.firstChild\n                .node\n                .siblings(true)\n                .dropWhile { it.elementType in dropChainValues }\n                .first()  // node treeNext is \".\", \"?.\", \"!!\", \"::\"\n            )\n        }\n    }\n\n    private fun KtBinaryExpression.dotCalls(right: Boolean = true) = (if (right) this.right else this.left)\n        ?.node\n        ?.takeIf { it.elementType == DOT_QUALIFIED_EXPRESSION }\n        ?.findChildByType(DOT)\n        ?.getCallChain()\n\n    private fun ASTNode.isElvisCorrect(): Boolean {\n        if (this.elementType != ELVIS) {\n            return false\n        }\n        val binaryExpression = (this.treeParent.treeParent.psi as KtBinaryExpression)\n        val leftDotCalls = binaryExpression.dotCalls(false)\n        val rightDotCalls = binaryExpression.dotCalls()\n        return (leftDotCalls?.size ?: 0) + (rightDotCalls?.size ?: 0) > configuration.maxCallsInOneLine && !this.isBeginByNewline()\n    }\n\n    /**\n     * This function is needed because many operators are represented as a single child of [OPERATION_REFERENCE] node\n     * e.g. [ANDAND] is a single child of [OPERATION_REFERENCE]\n     */\n    private fun ASTNode.selfOrOperationReferenceParent() = treeParent.takeIf { it.elementType == OPERATION_REFERENCE } ?: this\n\n    private fun ASTNode.isSingleDotStatementOnSingleLine() = parents()\n        .takeWhile { it.elementType in expressionTypes }\n        .singleOrNull()\n        ?.let { it.text.lines().count() == 1 }\n        ?: false\n\n    // fixme: there could be other cases when dot means something else\n    private fun ASTNode.isDotFromPackageOrImport() = elementType == DOT &&\n            parent(true) { it.elementType == IMPORT_DIRECTIVE || it.elementType == PACKAGE_DIRECTIVE } != null\n\n    private fun PsiElement.isFirstChildElementType(elementType: IElementType) =\n        this.firstChild.node.elementType == elementType\n\n    /**\n     * This method collects chain calls and checks it\n     *\n     * @return true - if there is error, and false if there is no error\n     */\n    private fun ASTNode.isInvalidCallsChain(dropLeadingProperties: Boolean = true) = getCallChain(dropLeadingProperties)?.isNotValidCalls(this) ?: false\n\n    private fun ASTNode.getCallChain(dropLeadingProperties: Boolean = true): List<ASTNode>? {\n        val parentExpressionList = getParentExpressions()\n            .lastOrNull()\n            ?.run {\n                mutableListOf<ASTNode>().also {\n                    getOrderedCallExpressions(psi, it)\n                }\n            }\n        return if (dropLeadingProperties) {\n            // fixme: we can't distinguish fully qualified names (like java.lang) from chain of property accesses (like list.size) for now\n            parentExpressionList?.dropWhile { !isTextContainsFunctionCall(it.treeParent) }\n        } else {\n            parentExpressionList\n        }\n    }\n\n    private fun isTextContainsFunctionCall(node: ASTNode): Boolean = node.textContains('(') || node.textContains('{')\n\n    private fun List<ASTNode>.isNotValidCalls(node: ASTNode): Boolean {\n        if (this.size == 1) {\n            return false\n        }\n        val callsByNewLine: ListOfList = mutableListOf()\n        val callsInOneNewLine: MutableList<ASTNode> = mutableListOf()\n        this.forEach { astNode ->\n            if (astNode.treePrev.isFollowedByNewline() || astNode.treePrev.isWhiteSpaceWithNewline()) {\n                callsByNewLine.add(callsInOneNewLine.toMutableList())\n                callsInOneNewLine.clear()\n            }\n            callsInOneNewLine.add(astNode)\n            if (astNode.treePrev.elementType == POSTFIX_EXPRESSION && !astNode.treePrev.isFollowedByNewline() && configuration.maxCallsInOneLine == 1) {\n                return true\n            }\n        }\n        callsByNewLine.add(callsInOneNewLine)\n        return (callsByNewLine.find { it.contains(node) } ?: return false)\n            .indexOf(node) + 1 > configuration.maxCallsInOneLine\n    }\n\n    /**\n     *  taking all expressions inside complex expression until we reach lambda arguments\n     */\n    private fun ASTNode.getParentExpressions() =\n        parents().takeWhile { it.elementType in chainExpressionTypes && it.elementType != LAMBDA_ARGUMENT }\n\n    private fun isMultilineLambda(node: ASTNode): Boolean =\n        (node.findAllDescendantsWithSpecificType(LAMBDA_ARGUMENT)\n            .firstOrNull()\n            ?.text\n            ?.count { it == '\\n' } ?: -1) > 0\n\n    /**\n     * Getting the first call expression in call chain\n     */\n    private fun ASTNode.isFirstCall() = getParentExpressions()\n        .lastOrNull()\n        ?.run {\n            val firstCallee = mutableListOf<ASTNode>().also {\n                getOrderedCallExpressions(psi, it)\n            }.first()\n            findAllDescendantsWithSpecificType(firstCallee.elementType, false).first() === this@isFirstCall\n        } ?: false\n\n    /**\n     * This method should be called on OPERATION_REFERENCE in the middle of BINARY_EXPRESSION\n     */\n    private fun ASTNode.isInfixCall() = elementType == OPERATION_REFERENCE &&\n            firstChildNode.elementType == IDENTIFIER &&\n            treeParent.elementType == BINARY_EXPRESSION\n\n    /**\n     * This method checks that complex expression should be replace with new variable\n     */\n    private fun ASTNode.isInParentheses() = parent { it.elementType == DOT_QUALIFIED_EXPRESSION || it.elementType == SAFE_ACCESS_EXPRESSION }\n        ?.treeParent\n        ?.elementType\n        ?.let { it in parenthesesTypes }\n        ?: false\n\n    /**\n     * [RuleConfiguration] for newlines placement\n     */\n    private class NewlinesRuleConfiguration(config: Map<String, String>) : RuleConfiguration(config) {\n        /**\n         * If the number of parameters on one line is more than this threshold, all parameters should be placed on separate lines.\n         */\n        val maxParametersInOneLine = config[\"maxParametersInOneLine\"]?.toInt() ?: 2\n        val maxCallsInOneLine = config[\"maxCallsInOneLine\"]?.toInt() ?: MAX_CALLS_IN_ONE_LINE\n    }\n\n    companion object {\n        private val log = KotlinLogging.logger {}\n        const val MAX_CALLS_IN_ONE_LINE = 3\n        const val NAME_ID = \"newlines\"\n\n        // fixme: these token sets can be not full, need to add new once as corresponding cases are discovered.\n        // error is raised if these operators are prepended by newline\n        private val lineBreakAfterOperators = TokenSet.create(ANDAND, OROR, PLUS, PLUSEQ, MINUS, MINUSEQ, MUL, MULTEQ, DIV, DIVEQ)\n        // error is raised if these operators are followed by newline\n\n        private val lineBreakBeforeOperators = TokenSet.create(DOT, SAFE_ACCESS, ELVIS, COLONCOLON)\n        private val expressionTypes = TokenSet.create(DOT_QUALIFIED_EXPRESSION, SAFE_ACCESS_EXPRESSION, CALLABLE_REFERENCE_EXPRESSION, BINARY_EXPRESSION)\n        private val chainExpressionTypes = TokenSet.create(DOT_QUALIFIED_EXPRESSION, SAFE_ACCESS_EXPRESSION)\n        private val dropChainValues = TokenSet.create(EOL_COMMENT, WHITE_SPACE, BLOCK_COMMENT, KDOC)\n        private val parenthesesTypes = TokenSet.create(CONDITION, WHEN, VALUE_ARGUMENT)\n    }\n}\n\n/**\n * Checks whether [this] function is recursive, i.e. calls itself inside from it's body\n *\n * @return true if function is recursive, false otherwise\n */\nfun KtNamedFunction.isRecursive() = bodyBlockExpression\n    ?.statements?.any { statement ->\n    statement.anyDescendantOfType<KtReferenceExpression> {\n        it.text == this@isRecursive.name\n    }\n}\n    ?: false\n"
  },
  {
    "path": "diktat-rules/src/main/kotlin/com/saveourtool/diktat/ruleset/rules/chapter3/files/SemicolonsRule.kt",
    "content": "package com.saveourtool.diktat.ruleset.rules.chapter3.files\n\nimport com.saveourtool.diktat.common.config.rules.RulesConfig\nimport com.saveourtool.diktat.ruleset.constants.Warnings.REDUNDANT_SEMICOLON\nimport com.saveourtool.diktat.ruleset.rules.DiktatRule\nimport com.saveourtool.diktat.ruleset.utils.extractLineOfText\nimport com.saveourtool.diktat.ruleset.utils.isEol\nimport org.jetbrains.kotlin.KtNodeTypes.ENUM_ENTRY\nimport org.jetbrains.kotlin.com.intellij.lang.ASTNode\nimport org.jetbrains.kotlin.lexer.KtTokens.SEMICOLON\n\n/**\n * Rule that checks usage of semicolons at the end of line\n */\n@Suppress(\"ForbiddenComment\")\nclass SemicolonsRule(configRules: List<RulesConfig>) : DiktatRule(\n    NAME_ID,\n    configRules,\n    listOf(REDUNDANT_SEMICOLON)\n) {\n    override fun logic(node: ASTNode) {\n        if (node.elementType == SEMICOLON) {\n            handleSemicolon(node)\n        }\n    }\n\n    /**\n     * Check that EOL semicolon is used only in enums\n     */\n    private fun handleSemicolon(node: ASTNode) {\n        if (node.isEol() && node.treeParent.elementType != ENUM_ENTRY) {\n            // semicolon at the end of line which is not part of enum members declarations\n            REDUNDANT_SEMICOLON.warnAndFix(configRules, emitWarn, isFixMode, node.extractLineOfText(), node.startOffset, node) {\n                node.treeParent.removeChild(node)\n            }\n        }\n    }\n\n    companion object {\n        const val NAME_ID = \"semicolon\"\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/main/kotlin/com/saveourtool/diktat/ruleset/rules/chapter3/files/TopLevelOrderRule.kt",
    "content": "package com.saveourtool.diktat.ruleset.rules.chapter3.files\n\nimport com.saveourtool.diktat.common.config.rules.RulesConfig\nimport com.saveourtool.diktat.ruleset.constants.Warnings.TOP_LEVEL_ORDER\nimport com.saveourtool.diktat.ruleset.rules.DiktatRule\nimport com.saveourtool.diktat.ruleset.utils.*\nimport com.saveourtool.diktat.ruleset.utils.isPartOfComment\n\nimport org.jetbrains.kotlin.KtNodeTypes.CLASS\nimport org.jetbrains.kotlin.KtNodeTypes.FUN\nimport org.jetbrains.kotlin.KtNodeTypes.IMPORT_LIST\nimport org.jetbrains.kotlin.KtNodeTypes.OBJECT_DECLARATION\nimport org.jetbrains.kotlin.KtNodeTypes.PROPERTY\nimport org.jetbrains.kotlin.KtNodeTypes.TYPEALIAS\nimport org.jetbrains.kotlin.com.intellij.lang.ASTNode\nimport org.jetbrains.kotlin.lexer.KtTokens.INTERNAL_KEYWORD\nimport org.jetbrains.kotlin.lexer.KtTokens.OVERRIDE_KEYWORD\nimport org.jetbrains.kotlin.lexer.KtTokens.PRIVATE_KEYWORD\nimport org.jetbrains.kotlin.lexer.KtTokens.PROTECTED_KEYWORD\nimport org.jetbrains.kotlin.lexer.KtTokens.WHITE_SPACE\nimport org.jetbrains.kotlin.psi.KtFunction\nimport org.jetbrains.kotlin.psi.psiUtil.isExtensionDeclaration\nimport org.jetbrains.kotlin.psi.psiUtil.siblings\nimport org.jetbrains.kotlin.psi.stubs.elements.KtFileElementType\n\n/**\n * Rule that checks order in top level\n */\nclass TopLevelOrderRule(configRules: List<RulesConfig>) : DiktatRule(\n    NAME_ID,\n    configRules,\n    listOf(TOP_LEVEL_ORDER),\n) {\n    override fun logic(node: ASTNode) {\n        if (node.elementType == KtFileElementType.INSTANCE) {\n            checkNode(node)\n        }\n    }\n\n    @Suppress(\"UnsafeCallOnNullableType\")\n    private fun checkNode(node: ASTNode) {\n        val children = node.getChildren(null)\n        val initialElementsOrder = children.filter { it.elementType in sortedType }\n        if (initialElementsOrder.isEmpty()) {\n            return\n        }\n        val properties = Properties(children.filter { it.elementType == PROPERTY }).sortElements()\n        val functions = children.filter { it.elementType == FUN }\n        val typealiases = children.filter { it.elementType == TYPEALIAS }\n        val classes = children.filter { it.elementType == CLASS || it.elementType == OBJECT_DECLARATION }\n        val sortedElementsWithTrailingNonCodeNodes = Blocks(properties, typealiases, functions, classes).sortElements().map { astNode ->\n            astNode to astNode.siblings(false).takeWhile { it.elementType == WHITE_SPACE || it.isPartOfComment() }.toList()\n        }\n        val lastNonSortedChildren = initialElementsOrder.last().siblings(true).toList()\n        sortedElementsWithTrailingNonCodeNodes.filterIndexed { index, pair -> initialElementsOrder[index] != pair.first }\n            .forEach { listOfChildren ->\n                val wrongNode = listOfChildren.first\n                TOP_LEVEL_ORDER.warnAndFix(configRules, emitWarn, isFixMode, wrongNode.text, wrongNode.startOffset, wrongNode) {\n                    node.removeRange(node.findChildByType(IMPORT_LIST)!!.treeNext, node.lastChildNode)\n                    node.removeChild(node.lastChildNode)\n                    sortedElementsWithTrailingNonCodeNodes.map { (sortedNode, sortedNodePrevSibling) ->\n                        sortedNodePrevSibling.reversed().map { node.addChild(it, null) }\n                        node.addChild(sortedNode, null)\n                    }\n                    lastNonSortedChildren.map { node.addChild(it, null) }\n                }\n            }\n    }\n\n    /**\n     * Interface for classes to collect child and sort them\n     */\n    interface Elements {\n        /**\n         * Method to sort children\n         *\n         * @return sorted mutable list\n         */\n        fun sortElements(): MutableList<ASTNode>\n    }\n\n    /**\n     * Class containing different groups of properties in file\n     *\n     * @param properties\n     */\n    private data class Properties(private val properties: List<ASTNode>) : Elements {\n        override fun sortElements(): MutableList<ASTNode> {\n            val constValProperties = properties.filter { it.isConstant() }\n            val valProperties = properties.filter { it.isValProperty() && !it.isConstant() }\n            val lateinitProperties = properties.filter { it.isLateInit() }\n            val varProperties = properties.filter { it.isVarProperty() && !it.isLateInit() }\n            return listOf(constValProperties, valProperties, lateinitProperties, varProperties).flatten().toMutableList()\n        }\n    }\n\n    /**\n     * Class containing different children in file\n     *\n     * @param properties\n     * @param typealiases\n     * @param functions\n     * @param classes\n     */\n    private data class Blocks(\n        private val properties: List<ASTNode>,\n        private val typealiases: List<ASTNode>,\n        private val functions: List<ASTNode>,\n        private val classes: List<ASTNode>\n    ) : Elements {\n        override fun sortElements(): MutableList<ASTNode> {\n            val (extensionFun, nonExtensionFun) = functions.partition { (it.psi as KtFunction).isExtensionDeclaration() }\n            return (properties + listOf(typealiases, classes, extensionFun, nonExtensionFun).flatMap { nodes ->\n                val (privatePart, notPrivatePart) = nodes.partition { it.hasModifier(PRIVATE_KEYWORD) }\n                val (protectedPart, notProtectedPart) = notPrivatePart.partition { it.hasModifier(PROTECTED_KEYWORD) || it.hasModifier(OVERRIDE_KEYWORD) }\n                val (internalPart, publicPart) = notProtectedPart.partition { it.hasModifier(INTERNAL_KEYWORD) }\n                listOf(publicPart, internalPart, protectedPart, privatePart).flatten()\n            }).toMutableList()\n        }\n    }\n\n    companion object {\n        const val NAME_ID = \"top-level-order\"\n\n        /**\n         * List of children that should be sort\n         */\n        val sortedType = listOf(PROPERTY, FUN, CLASS, OBJECT_DECLARATION, TYPEALIAS)\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/main/kotlin/com/saveourtool/diktat/ruleset/rules/chapter3/files/WhiteSpaceRule.kt",
    "content": "package com.saveourtool.diktat.ruleset.rules.chapter3.files\n\nimport com.saveourtool.diktat.common.config.rules.RulesConfig\nimport com.saveourtool.diktat.common.config.rules.getRuleConfig\nimport com.saveourtool.diktat.ruleset.constants.Warnings.LONG_LINE\nimport com.saveourtool.diktat.ruleset.constants.Warnings.WRONG_INDENTATION\nimport com.saveourtool.diktat.ruleset.constants.Warnings.WRONG_WHITESPACE\nimport com.saveourtool.diktat.ruleset.rules.DiktatRule\nimport com.saveourtool.diktat.ruleset.rules.chapter3.LineLength\nimport com.saveourtool.diktat.ruleset.utils.appendNewlineMergingWhiteSpace\nimport com.saveourtool.diktat.ruleset.utils.calculateLineColByOffset\nimport com.saveourtool.diktat.ruleset.utils.findParentNodeWithSpecificType\nimport com.saveourtool.diktat.ruleset.utils.hasChildOfType\nimport com.saveourtool.diktat.ruleset.utils.isPartOfComment\nimport com.saveourtool.diktat.ruleset.utils.isWhiteSpace\nimport com.saveourtool.diktat.ruleset.utils.nextCodeLeaf\nimport com.saveourtool.diktat.ruleset.utils.parent\nimport com.saveourtool.diktat.ruleset.utils.prevSibling\n\nimport io.github.oshai.kotlinlogging.KotlinLogging\nimport org.jetbrains.kotlin.KtNodeTypes.ANNOTATION_ENTRY\nimport org.jetbrains.kotlin.KtNodeTypes.BINARY_EXPRESSION\nimport org.jetbrains.kotlin.KtNodeTypes.BLOCK\nimport org.jetbrains.kotlin.KtNodeTypes.CALLABLE_REFERENCE_EXPRESSION\nimport org.jetbrains.kotlin.KtNodeTypes.CALL_EXPRESSION\nimport org.jetbrains.kotlin.KtNodeTypes.CLASS\nimport org.jetbrains.kotlin.KtNodeTypes.COLLECTION_LITERAL_EXPRESSION\nimport org.jetbrains.kotlin.KtNodeTypes.CONSTRUCTOR_DELEGATION_CALL\nimport org.jetbrains.kotlin.KtNodeTypes.FUN\nimport org.jetbrains.kotlin.KtNodeTypes.FUNCTION_LITERAL\nimport org.jetbrains.kotlin.KtNodeTypes.LAMBDA_EXPRESSION\nimport org.jetbrains.kotlin.KtNodeTypes.NULLABLE_TYPE\nimport org.jetbrains.kotlin.KtNodeTypes.OBJECT_DECLARATION\nimport org.jetbrains.kotlin.KtNodeTypes.OPERATION_REFERENCE\nimport org.jetbrains.kotlin.KtNodeTypes.POSTFIX_EXPRESSION\nimport org.jetbrains.kotlin.KtNodeTypes.PRIMARY_CONSTRUCTOR\nimport org.jetbrains.kotlin.KtNodeTypes.PROPERTY\nimport org.jetbrains.kotlin.KtNodeTypes.SECONDARY_CONSTRUCTOR\nimport org.jetbrains.kotlin.KtNodeTypes.TYPE_CONSTRAINT\nimport org.jetbrains.kotlin.KtNodeTypes.TYPE_PARAMETER\nimport org.jetbrains.kotlin.KtNodeTypes.TYPE_PARAMETER_LIST\nimport org.jetbrains.kotlin.KtNodeTypes.VALUE_ARGUMENT\nimport org.jetbrains.kotlin.KtNodeTypes.VALUE_ARGUMENT_LIST\nimport org.jetbrains.kotlin.KtNodeTypes.VALUE_PARAMETER\nimport org.jetbrains.kotlin.KtNodeTypes.VALUE_PARAMETER_LIST\nimport org.jetbrains.kotlin.com.intellij.lang.ASTNode\nimport org.jetbrains.kotlin.com.intellij.psi.impl.source.tree.LeafElement\nimport org.jetbrains.kotlin.com.intellij.psi.impl.source.tree.PsiWhiteSpaceImpl\nimport org.jetbrains.kotlin.com.intellij.psi.tree.TokenSet\nimport org.jetbrains.kotlin.lexer.KtTokens.ARROW\nimport org.jetbrains.kotlin.lexer.KtTokens.CATCH_KEYWORD\nimport org.jetbrains.kotlin.lexer.KtTokens.COLON\nimport org.jetbrains.kotlin.lexer.KtTokens.COLONCOLON\nimport org.jetbrains.kotlin.lexer.KtTokens.COMMA\nimport org.jetbrains.kotlin.lexer.KtTokens.CONSTRUCTOR_KEYWORD\nimport org.jetbrains.kotlin.lexer.KtTokens.DOT\nimport org.jetbrains.kotlin.lexer.KtTokens.DO_KEYWORD\nimport org.jetbrains.kotlin.lexer.KtTokens.ELSE_KEYWORD\nimport org.jetbrains.kotlin.lexer.KtTokens.ELVIS\nimport org.jetbrains.kotlin.lexer.KtTokens.EQ\nimport org.jetbrains.kotlin.lexer.KtTokens.EXCLEXCL\nimport org.jetbrains.kotlin.lexer.KtTokens.FINALLY_KEYWORD\nimport org.jetbrains.kotlin.lexer.KtTokens.FOR_KEYWORD\nimport org.jetbrains.kotlin.lexer.KtTokens.GT\nimport org.jetbrains.kotlin.lexer.KtTokens.IF_KEYWORD\nimport org.jetbrains.kotlin.lexer.KtTokens.INIT_KEYWORD\nimport org.jetbrains.kotlin.lexer.KtTokens.LBRACE\nimport org.jetbrains.kotlin.lexer.KtTokens.LBRACKET\nimport org.jetbrains.kotlin.lexer.KtTokens.LPAR\nimport org.jetbrains.kotlin.lexer.KtTokens.LT\nimport org.jetbrains.kotlin.lexer.KtTokens.QUEST\nimport org.jetbrains.kotlin.lexer.KtTokens.RANGE\nimport org.jetbrains.kotlin.lexer.KtTokens.RBRACE\nimport org.jetbrains.kotlin.lexer.KtTokens.RBRACKET\nimport org.jetbrains.kotlin.lexer.KtTokens.RPAR\nimport org.jetbrains.kotlin.lexer.KtTokens.SAFE_ACCESS\nimport org.jetbrains.kotlin.lexer.KtTokens.SEMICOLON\nimport org.jetbrains.kotlin.lexer.KtTokens.TRY_KEYWORD\nimport org.jetbrains.kotlin.lexer.KtTokens.WHEN_KEYWORD\nimport org.jetbrains.kotlin.lexer.KtTokens.WHILE_KEYWORD\nimport org.jetbrains.kotlin.lexer.KtTokens.WHITE_SPACE\nimport org.jetbrains.kotlin.psi.KtBinaryExpression\nimport org.jetbrains.kotlin.psi.KtPostfixExpression\nimport org.jetbrains.kotlin.psi.KtPrefixExpression\nimport org.jetbrains.kotlin.psi.psiUtil.parents\nimport org.jetbrains.kotlin.psi.psiUtil.parentsWithSelf\nimport org.jetbrains.kotlin.psi.stubs.elements.KtFileElementType\n\n/**\n * This rule checks usage of whitespaces for horizontal code separation\n * 1. There should be single space between keyword and (, unless keyword is `constructor`\n * 2. There should be single space between keyword and {\n * 3. There should be single space before any {, unless lambda inside parentheses of argument list\n * 4. Binary operators should be surrounded by whitespaces, excluding :: and .\n * 5. Spaces should be used after `,`, `:`, `;` (except cases when those symbols are in the end of line).\n *    There should be no whitespaces in the end of line.\n * 6. There should be only one space between identifier and it's type, if type is nullable there should be no spaces before `?`\n * 7. There should be no space before `[`\n * 8. There should be no space between a method or constructor name (both at declaration and at call site) and a parenthesis.\n * 9. There should be no space after `(`, `[` and `<` (in templates); no space before `)`, `]`, `>` (in templates)\n * 10. There should be no spaces between prefix/postfix operator (like `!!` or `++`) and it's operand\n */\n@Suppress(\"ForbiddenComment\")\nclass WhiteSpaceRule(configRules: List<RulesConfig>) : DiktatRule(\n    NAME_ID,\n    configRules,\n    listOf(WRONG_WHITESPACE, LONG_LINE, WRONG_INDENTATION)\n) {\n    private val configuration by lazy {\n        LineLength.LineLengthConfiguration(\n            configRules.getRuleConfig(LONG_LINE)?.configuration ?: emptyMap()\n        )\n    }\n    private lateinit var positionByOffset: (Int) -> Pair<Int, Int>\n    @Suppress(\"ComplexMethod\")\n    override fun logic(node: ASTNode) {\n        when (node.elementType) {\n            // keywords\n            CONSTRUCTOR_KEYWORD -> handleConstructor(node)\n            in keywordsWithSpaceAfter -> handleKeywordWithParOrBrace(node)\n            // operators and operator-like symbols\n            DOT, ARROW, SAFE_ACCESS, EQ -> handleBinaryOperator(node)\n            OPERATION_REFERENCE -> handleOperator(node)\n            COLON -> handleColon(node)\n            COLONCOLON -> handleColonColon(node)\n            COMMA, SEMICOLON -> handleToken(node, 0, 1)\n            QUEST -> if (node.treeParent.elementType == NULLABLE_TYPE) {\n                handleToken(node, 0, null)\n            }\n            // braces and other symbols\n            LBRACE -> handleLbrace(node)\n            RBRACE -> handleRbrace(node)\n            LBRACKET -> handleLbracket(node)\n            LPAR -> handleLpar(node)\n            RPAR, RBRACKET -> handleToken(node, 0, null)\n            GT, LT -> handleGtOrLt(node)\n            // white space\n            WHITE_SPACE -> handleEolWhiteSpace(node)\n            else -> {\n            }\n        }\n    }\n\n    private fun handleLbracket(node: ASTNode) =\n        if (node.treeParent.elementType == COLLECTION_LITERAL_EXPRESSION) {\n            handleToken(node, 1, 0)\n        } else {\n            handleToken(node, 0, 0)\n        }\n\n    private fun handleConstructor(node: ASTNode) {\n        if (node.treeNext.numWhiteSpaces()?.let { it > 0 } == true) {\n            // there is either whitespace or newline after constructor keyword\n            WRONG_WHITESPACE.warnAndFix(configRules, emitWarn, isFixMode, \"keyword '${node.text}' should not be separated from \" +\n                    \"'(' with a whitespace\", node.startOffset, node) {\n                node.treeParent.removeChild(node.treeNext)\n            }\n        }\n    }\n\n    @Suppress(\"UnsafeCallOnNullableType\")\n    private fun handleKeywordWithParOrBrace(node: ASTNode) {\n        if (node.treeNext.numWhiteSpaces() != 1) {\n            // there is either not single whitespace or newline after keyword\n            val nextCodeLeaf = node.nextCodeLeaf()!!\n            if (nextCodeLeaf.elementType != LPAR && nextCodeLeaf.elementType != LBRACE && node.treeNext.textContains('\\n')) {\n                // statement after keyword doesn't have braces and starts at new line, e.g. `if (condition) foo()\\n else\\n bar()`\n                return\n            }\n            WRONG_WHITESPACE.warnAndFix(configRules, emitWarn, isFixMode, \"keyword '${node.text}' should be separated from \" +\n                    \"'${nextCodeLeaf.text}' with a whitespace\", nextCodeLeaf.startOffset, nextCodeLeaf) {\n                node.leaveSingleWhiteSpace()\n            }\n        }\n    }\n\n    private fun handleRbrace(node: ASTNode) {\n        if (node.treeParent.elementType == FUNCTION_LITERAL &&\n                !node.treePrev.isWhiteSpace() &&\n                node.treePrev.elementType == BLOCK &&\n                node.treePrev.text.isNotEmpty()) {\n            WRONG_WHITESPACE.warnAndFix(configRules, emitWarn, isFixMode, \"there should be a whitespace before }\", node.startOffset, node) {\n                node.treeParent.addChild(PsiWhiteSpaceImpl(\" \"), node)\n            }\n        }\n    }\n\n    /**\n     * This method covers all other opening braces, not covered in [handleKeywordWithParOrBrace].\n     */\n    @Suppress(\"UnsafeCallOnNullableType\")\n    private fun handleLbrace(node: ASTNode) {\n        // `{` can't be the very first symbol in the file, so `!!` should be safe\n        val whitespaceOrPrevNode = node.selfOrParentsTreePrev()!!\n        val isFromLambdaAsArgument = node\n            .parents()\n            .take(NUM_PARENTS_FOR_LAMBDA)\n            .toList()\n            .takeIf { it.size == NUM_PARENTS_FOR_LAMBDA }\n            ?.let {\n                it[0].elementType == FUNCTION_LITERAL &&\n                        it[1].elementType == LAMBDA_EXPRESSION &&\n                        it[2].elementType == VALUE_ARGUMENT &&\n                        // lambda is not passed as a named argument\n                        !it[2].hasChildOfType(EQ)\n            }\n            ?: false\n\n        val prevNode = whitespaceOrPrevNode.let { if (it.elementType == WHITE_SPACE) it.treePrev else it }\n        val numWhiteSpace = whitespaceOrPrevNode.numWhiteSpaces()\n        handleWhiteSpaceBeforeLeftBrace(node, isFromLambdaAsArgument, numWhiteSpace, whitespaceOrPrevNode, prevNode)\n        handleWhiteSpaceAfterLeftBrace(node)\n    }\n\n    private fun handleWhiteSpaceBeforeLeftBrace(node: ASTNode,\n                                                isFromLambdaAsArgument: Boolean,\n                                                numWhiteSpace: Int?,\n                                                whitespaceOrPrevNode: ASTNode,\n                                                prevNode: ASTNode\n    ) {\n        // note: the conditions in the following `if`s cannot be collapsed into simple conjunctions\n        if (isFromLambdaAsArgument) {\n            @Suppress(\"PARAMETER_NAME_IN_OUTER_LAMBDA\")\n            val isFirstArgument = node\n                .parent { it.elementType == VALUE_ARGUMENT }\n                .let { it?.prevSibling { prevNode -> prevNode.elementType == COMMA } == null }\n\n            // Handling this case: `foo({ it.bar() }, 2, 3)`\n            if (numWhiteSpace != 0 && isFirstArgument) {\n                WRONG_WHITESPACE.warnAndFix(configRules, emitWarn, isFixMode, \"there should be no whitespace before '{' of lambda\" +\n                        \" inside argument list\", node.startOffset, node) {\n                    whitespaceOrPrevNode.treeParent.removeChild(whitespaceOrPrevNode)\n                }\n            }\n        } else if (prevNode.elementType !in keywordsWithSpaceAfter && numWhiteSpace != 1) {\n            val hasOnlyWhiteSpaceBefore = whitespaceOrPrevNode.elementType == WHITE_SPACE && whitespaceOrPrevNode.textContains('\\n')\n            if (!hasOnlyWhiteSpaceBefore) {\n                WRONG_WHITESPACE.warnAndFix(configRules, emitWarn, isFixMode, \"there should be a whitespace before '{'\", node.startOffset, node) {\n                    prevNode.leaveSingleWhiteSpace()\n                }\n            }\n        }\n    }\n\n    private fun handleWhiteSpaceAfterLeftBrace(node: ASTNode) {\n        if (node.treeParent.elementType == FUNCTION_LITERAL && !node.treeNext.isWhiteSpace() &&\n                node.treeNext.elementType == BLOCK && node.treeNext.text.isNotEmpty()) {\n            WRONG_WHITESPACE.warnAndFix(configRules, emitWarn, isFixMode, \"there should be a whitespace after {\", node.startOffset, node) {\n                node.treeParent.addChild(PsiWhiteSpaceImpl(\" \"), node.treeNext)\n            }\n        }\n    }\n\n    private fun handleColonColon(node: ASTNode) {\n        if (node.treeParent.elementType == CALLABLE_REFERENCE_EXPRESSION) {\n            if (node.treeParent.firstChildNode != node) {\n                // callable reference has receiver and shouldn't have any spaces around\n                handleBinaryOperator(node)\n            } else {\n                // callable reference doesn't have receiver, it should stick to reference name and spaces before are determined\n                // by other cases of this rule\n                handleToken(node, null, 0)\n            }\n        }\n    }\n\n    private fun handleColon(node: ASTNode) {\n        when (node.treeParent.elementType) {\n            CLASS, SECONDARY_CONSTRUCTOR, TYPE_CONSTRAINT, TYPE_PARAMETER, OBJECT_DECLARATION -> handleBinaryOperator(node)\n            VALUE_PARAMETER, PROPERTY, FUN -> handleToken(node, 0, 1)\n            ANNOTATION_ENTRY -> handleToken(node, 0, 0)  // e.g. @param:JsonProperty\n            // fixme: find examples or delete this line\n            else -> log.warn { \"Colon with treeParent.elementType=${node.treeParent.elementType}, not handled by WhiteSpaceRule\" }\n        }\n    }\n\n    private fun handleOperator(node: ASTNode) {\n        when (node.treeParent.psi) {\n            is KtPrefixExpression -> handleToken(node, null, 0)\n            is KtPostfixExpression -> handleToken(node, 0, null)\n            is KtBinaryExpression -> handleBinaryOperator(node)\n            else -> {\n            }\n        }\n    }\n\n    private fun handleBinaryOperator(node: ASTNode) {\n        val operatorNode = if (node.elementType == OPERATION_REFERENCE) node.firstChildNode else node\n        if (node.elementType == EQ && node.treeParent.elementType == OPERATION_REFERENCE) {\n            return\n        }\n        if (node.elementType == OPERATION_REFERENCE && node.treeParent.elementType.let { it == BINARY_EXPRESSION || it == POSTFIX_EXPRESSION || it == PROPERTY } ||\n                node.elementType != OPERATION_REFERENCE) {\n            val requiredNumSpaces = if (operatorNode.elementType in operatorsWithNoWhitespace) 0 else 1\n            handleToken(node, requiredNumSpaces, requiredNumSpaces)\n        }\n    }\n\n    @Suppress(\"UnsafeCallOnNullableType\")\n    private fun handleToken(\n        node: ASTNode,\n        requiredSpacesBefore: Int?,\n        requiredSpacesAfter: Int?\n    ) {\n        require(requiredSpacesBefore != null || requiredSpacesAfter != null) {\n            \"requiredSpacesBefore=$requiredSpacesBefore and requiredSpacesAfter=$requiredSpacesAfter, but at least one should not be null\"\n        }\n        val spacesBefore = node.selfOrParentsTreePrev()!!.numWhiteSpaces()\n        // calculate actual spaces after but only if requiredSpacesAfter is not null, otherwise we won't check it\n        val spacesAfter = requiredSpacesAfter?.let { _ ->\n            // for `!!` and possibly other postfix expressions treeNext and treeParent.treeNext can be null\n            // upper levels are already outside of the expression this token belongs to, so we won't check them\n            (node.treeNext\n                ?: node.treeParent.treeNext)\n                ?.numWhiteSpaces()\n        }\n        val isErrorBefore = requiredSpacesBefore != null && spacesBefore != null && spacesBefore != requiredSpacesBefore\n        val isErrorAfter = requiredSpacesAfter != null && spacesAfter != null && spacesAfter != requiredSpacesAfter\n        if (isErrorBefore || isErrorAfter) {\n            val freeText = \"${node.text} should have\" +\n                    getDescription(requiredSpacesBefore != null, requiredSpacesAfter != null, requiredSpacesBefore, requiredSpacesAfter) +\n                    \", but has\" +\n                    getDescription(isErrorBefore, isErrorAfter, spacesBefore, spacesAfter)\n            WRONG_WHITESPACE.warnAndFix(configRules, emitWarn, isFixMode, freeText, node.startOffset, node) {\n                node.fixSpaceAround(requiredSpacesBefore, requiredSpacesAfter)\n            }\n        }\n    }\n\n    private fun handleEolWhiteSpace(node: ASTNode) {\n        val hasSpaces = node.text.substringBefore('\\n').contains(' ')\n        // the second condition corresponds to the last line of file\n        val isEol = node.textContains('\\n') || node.psi.parentsWithSelf.all { it.nextSibling == null }\n        if (hasSpaces && isEol) {\n            WRONG_WHITESPACE.warnAndFix(configRules, emitWarn, isFixMode, \"there should be no spaces in the end of line\", node.startOffset, node) {\n                (node as LeafElement).rawReplaceWithText(node.text.trimStart(' '))\n            }\n        }\n    }\n\n    @Suppress(\"UnsafeCallOnNullableType\")\n    private fun handleLpar(node: ASTNode) {\n        when {\n            node.treeParent.treeParent.elementType == SECONDARY_CONSTRUCTOR -> {\n                // there is separate handler for 'constructor' keyword to provide custom warning message\n                return\n            }\n            node.nextCodeLeaf()!!.elementType == LBRACE -> {\n                // there is separate handler for lambda expression inside parenthesis\n                return\n            }\n            node.treeParent.treeParent.elementType == ANNOTATION_ENTRY ->\n                handleToken(node.treeParent, 0, null)\n            else -> {\n            }\n        }\n        val isDeclaration = node.treeParent.elementType == VALUE_PARAMETER_LIST && node.treeParent\n            .treeParent\n            .elementType\n            .let {\n                it == PRIMARY_CONSTRUCTOR || it == FUN || it == CALL_EXPRESSION\n            }\n        val isCall = node.treeParent.elementType == VALUE_ARGUMENT_LIST && node.treeParent\n            .treeParent\n            .elementType\n            .let {\n                it == CONSTRUCTOR_DELEGATION_CALL || it == CALL_EXPRESSION\n            }\n        if (isDeclaration || isCall) {\n            handleToken(node, 0, 0)\n        } else {\n            handleToken(node, null, 0)\n        }\n    }\n\n    private fun handleGtOrLt(node: ASTNode) {\n        if (node.treeParent == TYPE_PARAMETER_LIST) {\n            handleToken(\n                node,\n                if (node.elementType == GT) 0 else null,\n                if (node.elementType == GT) null else 0\n            )\n        }\n    }\n\n    @Suppress(\"UnsafeCallOnNullableType\")\n    private fun ASTNode.isNeedNewLineInOperatorReferences(): Boolean {\n        positionByOffset = this.findParentNodeWithSpecificType(KtFileElementType.INSTANCE)!!.calculateLineColByOffset()\n        val offset = positionByOffset(this.startOffset).second\n        return offset + this.text.length >= configuration.lineLength\n    }\n\n    @Suppress(\"UnsafeCallOnNullableType\")\n    private fun ASTNode.fixSpaceAround(requiredSpacesBefore: Int?, requiredSpacesAfter: Int?) {\n        if (requiredSpacesBefore == 1) {\n            selfOrParentsTreePrev()?.let { if (it.elementType == WHITE_SPACE) it.treePrev else it }?.leaveSingleWhiteSpace()\n            if (this.isNeedNewLineInOperatorReferences() && this.firstChildNode.elementType == ELVIS) {\n                this.treePrev.let { this.treeParent.appendNewlineMergingWhiteSpace(it, it) }\n            }\n        } else if (requiredSpacesBefore == 0) {\n            selfOrParentsTreePrev()?.removeIfWhiteSpace()\n        }\n        if (requiredSpacesAfter == 1) {\n            leaveSingleWhiteSpace()\n            if (this.isNeedNewLineInOperatorReferences() && this.firstChildNode.elementType != ELVIS) {\n                this.treeNext.let { this.treeParent.appendNewlineMergingWhiteSpace(it, it) }\n            }\n        } else if (requiredSpacesAfter == 0) {\n            // for `!!` and possibly other postfix expressions treeNext can be null\n            (treeNext ?: treeParent.treeNext).removeIfWhiteSpace()\n        }\n    }\n\n    /**\n     * Function that returns `treePrev` of this node, or if this.treePrev is null, `treePrev` of first parent node that has it\n     */\n    private fun ASTNode.selfOrParentsTreePrev() = parent(false) { it.treePrev != null }?.treePrev\n\n    /**\n     * This method counts spaces in this node. Null is returned in following cases:\n     * * if it is WHITE_SPACE with a newline\n     * * if the next node is a comment, because spaces around comments are checked elsewhere.\n     *\n     * If this node is not a WHITE_SPACE, 0 is returned because there are zero white spaces.\n     */\n    private fun ASTNode.numWhiteSpaces(): Int? = if (elementType != WHITE_SPACE) {\n        0\n    } else {\n        // this can happen, e.g. in lambdas after an arrow, where block can be not surrounded by braces\n        // treeNext may not have children ( {_, _ -> })\n        val isBlockStartingWithComment = treeNext.elementType == BLOCK && treeNext.firstChildNode?.isPartOfComment() == true\n        if (textContains('\\n') || treeNext.isPartOfComment() || isBlockStartingWithComment) null else text.count { it == ' ' }\n    }\n\n    private fun ASTNode.leaveSingleWhiteSpace() {\n        if (treeNext.elementType == WHITE_SPACE) {\n            (treeNext as LeafElement).rawReplaceWithText(\" \")\n        } else {\n            treeParent.addChild(PsiWhiteSpaceImpl(\" \"), treeNext)\n        }\n    }\n\n    private fun ASTNode.removeIfWhiteSpace() = takeIf { it.elementType == WHITE_SPACE && !it.textContains('\\n') }\n        ?.let { it.treeParent.removeChild(it) }\n\n    private fun getDescription(shouldBefore: Boolean,\n                               shouldAfter: Boolean,\n                               before: Int?,\n                               after: Int?\n    ): String =\n        if (shouldBefore && shouldAfter) {\n            \" $before space(s) before and $after space(s) after\"\n        } else if (shouldBefore && !shouldAfter) {\n            \" $before space(s) before\"\n        } else if (shouldAfter) {\n            \" $after space(s) after\"\n        } else {\n            \"\"\n        }\n\n    companion object {\n        private val log = KotlinLogging.logger {}\n        const val NAME_ID = \"horizontal-whitespace\"\n\n        // this is the number of parent nodes needed to check if this node is lambda from argument list\n        private const val NUM_PARENTS_FOR_LAMBDA = 3\n        private val keywordsWithSpaceAfter = TokenSet.create(\n            // these keywords are followed by {\n            ELSE_KEYWORD, TRY_KEYWORD, DO_KEYWORD, FINALLY_KEYWORD, INIT_KEYWORD,\n            // these keywords are followed by (\n            FOR_KEYWORD, IF_KEYWORD, WHILE_KEYWORD, CATCH_KEYWORD,\n            // these keywords can be followed by either { or (\n            WHEN_KEYWORD\n        )\n        val operatorsWithNoWhitespace = TokenSet.create(DOT, RANGE, COLONCOLON, SAFE_ACCESS, EXCLEXCL)\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/main/kotlin/com/saveourtool/diktat/ruleset/rules/chapter3/identifiers/LocalVariablesRule.kt",
    "content": "package com.saveourtool.diktat.ruleset.rules.chapter3.identifiers\n\nimport com.saveourtool.diktat.common.config.rules.RulesConfig\nimport com.saveourtool.diktat.ruleset.constants.Warnings.LOCAL_VARIABLE_EARLY_DECLARATION\nimport com.saveourtool.diktat.ruleset.rules.DiktatRule\nimport com.saveourtool.diktat.ruleset.utils.containsOnlyConstants\nimport com.saveourtool.diktat.ruleset.utils.getDeclarationScope\nimport com.saveourtool.diktat.ruleset.utils.getLineNumber\nimport com.saveourtool.diktat.ruleset.utils.isPartOfComment\nimport com.saveourtool.diktat.ruleset.utils.lastLineNumber\nimport com.saveourtool.diktat.ruleset.utils.numNewLines\nimport com.saveourtool.diktat.ruleset.utils.search.findAllVariablesWithUsages\n\nimport org.jetbrains.kotlin.com.intellij.lang.ASTNode\nimport org.jetbrains.kotlin.com.intellij.psi.PsiElement\nimport org.jetbrains.kotlin.com.intellij.psi.PsiWhiteSpace\nimport org.jetbrains.kotlin.lexer.KtTokens.SEMICOLON\nimport org.jetbrains.kotlin.lexer.KtTokens.WHITE_SPACE\nimport org.jetbrains.kotlin.psi.KtBlockExpression\nimport org.jetbrains.kotlin.psi.KtCallExpression\nimport org.jetbrains.kotlin.psi.KtNameReferenceExpression\nimport org.jetbrains.kotlin.psi.KtProperty\nimport org.jetbrains.kotlin.psi.psiUtil.getParentOfType\nimport org.jetbrains.kotlin.psi.psiUtil.parents\nimport org.jetbrains.kotlin.psi.psiUtil.parentsWithSelf\nimport org.jetbrains.kotlin.psi.psiUtil.referenceExpression\nimport org.jetbrains.kotlin.psi.psiUtil.siblings\nimport org.jetbrains.kotlin.psi.psiUtil.startOffset\nimport org.jetbrains.kotlin.psi.stubs.elements.KtFileElementType\n\n/**\n * This rule checks that local variables are declared close to the point where they are first used.\n * Current algorithm assumes that scopes are always `BLOCK`s.\n * 1. Warns if there are statements between variable declaration and it's first usage\n * 2. It is allowed to declare variables in outer scope compared to usage scope. It could be useful to store state, e.g. between loop iterations.\n *\n * Current limitations due to usage of AST only:\n * * Only properties without initialization or initialized with expressions based on constants are supported.\n * * Properties initialized with constructor calls cannot be distinguished from method call and are no supported.\n */\nclass LocalVariablesRule(configRules: List<RulesConfig>) : DiktatRule(\n    NAME_ID,\n    configRules,\n    listOf(LOCAL_VARIABLE_EARLY_DECLARATION)\n) {\n    override fun logic(node: ASTNode) {\n        if (node.elementType == KtFileElementType.INSTANCE) {\n            // collect all local properties and associate with corresponding references\n            val propertiesToUsages = collectLocalPropertiesWithUsages(node)\n\n            // find all usages which include more than one property\n            val multiPropertyUsages = groupPropertiesByUsages(propertiesToUsages)\n\n            multiPropertyUsages\n                .forEach { (statement, properties) ->\n                    handleConsecutiveDeclarations(statement, properties)\n                }\n\n            propertiesToUsages\n                .filterNot { it.key in multiPropertyUsages.values.flatten() }\n                .forEach { handleLocalProperty(it.key, it.value) }\n        }\n    }\n\n    private fun collectLocalPropertiesWithUsages(node: ASTNode) = node\n        .findAllVariablesWithUsages { propertyNode ->\n            propertyNode.isLocal && propertyNode.name != null && propertyNode.parent is KtBlockExpression &&\n                    (propertyNode.isVar && propertyNode.initializer == null ||\n                            (propertyNode.initializer?.containsOnlyConstants() ?: false) ||\n                            (propertyNode.initializer as? KtCallExpression).isWhitelistedMethod())\n        }\n\n        .filterNot { it.value.isEmpty() }\n\n    @Suppress(\"TYPE_ALIAS\")\n    private fun groupPropertiesByUsages(propertiesToUsages: Map<KtProperty, List<KtNameReferenceExpression>>) = propertiesToUsages\n        .mapValues { (property, usages) ->\n            getFirstUsageStatementOrBlock(usages, property.getDeclarationScope())\n        }\n        .map { it.value to it.key }\n        .groupByTo(mutableMapOf(), { it.first }) { it.second }\n        .filter { it.value.size > 1 }\n        .toMap<PsiElement, List<KtProperty>>()\n\n    @Suppress(\"UnsafeCallOnNullableType\")\n    private fun handleLocalProperty(property: KtProperty, usages: List<KtNameReferenceExpression>) {\n        val declarationScope = property.getDeclarationScope()\n\n        val firstUsageStatementLine = getFirstUsageStatementOrBlock(usages, declarationScope).node.getLineNumber()\n        val firstUsage = usages.minByOrNull { it.node.getLineNumber() }!!\n\n        // should skip val and var before it's statement\n        val offset = property\n            .siblings(forward = true, withItself = false)\n            .takeWhile { it != getFirstUsageStatementOrBlock(usages, declarationScope) }\n            .filter { it is KtProperty }\n            .count()\n        checkLineNumbers(property, firstUsageStatementLine, firstUsageLine = firstUsage.node.getLineNumber(), offset = offset)\n    }\n\n    /**\n     * Check declarations, for which the properties are used on the same line.\n     * If properties are used for the first time in the same statement, then they can be declared on consecutive lines\n     * with maybe empty lines in between.\n     */\n    @Suppress(\"TOO_LONG_FUNCTION\")\n    private fun handleConsecutiveDeclarations(statement: PsiElement, properties: List<KtProperty>) {\n        val numLinesAfterLastProp =\n            properties\n                .last()\n                .node\n                .treeNext\n                .takeIf { it.elementType == WHITE_SPACE }\n                ?.let {\n                    // minus one is needed to except \\n after property\n                    it.numNewLines() - 1\n                }\n                ?: 0\n\n        val sortedProperties = properties.sortedBy { it.node.getLineNumber() }\n        // need to check that properties are declared consecutively with only maybe empty lines\n        sortedProperties\n            .zip(\n                (properties.size - 1 downTo 0).map { index ->\n                    val siblings = sortedProperties[properties.lastIndex - index].siblings(forward = true, withItself = false)\n\n                    // Also we need to count number of comments to skip. See `should skip comments` test\n                    // For the last property we don't need to count, because they will be counted in checkLineNumbers\n                    // We count number of comments beginning from next property\n                    val numberOfComments = siblings\n                        .takeWhile { it != statement }\n                        .dropWhile { it !is KtProperty }\n                        .filter { it.node.isPartOfComment() }\n                        .count()\n\n                    // We should also skip all vars that were not included in properties list, but they are between statement and current property\n                    val numberOfVarWithInitializer = siblings\n                        .takeWhile { it != statement }\n                        .filter { it is KtProperty && it !in properties }\n                        .count()\n\n                    // If it is not last property we should consider number on new lines after last property in list\n                    if (index != 0) {\n                        index + numLinesAfterLastProp + numberOfComments + numberOfVarWithInitializer\n                    } else {\n                        index + numberOfComments + numberOfVarWithInitializer\n                    }\n                }\n            )\n            .forEach { (property, offset) ->\n                checkLineNumbers(property, statement.node.getLineNumber(), offset)\n            }\n    }\n\n    @Suppress(\"UnsafeCallOnNullableType\")\n    private fun checkLineNumbers(\n        property: KtProperty,\n        firstUsageStatementLine: Int,\n        offset: Int = 0,\n        firstUsageLine: Int? = null\n    ) {\n        val numLinesToSkip = property\n            .siblings(forward = true, withItself = false)\n            .takeWhile { it is PsiWhiteSpace || it.node.elementType == SEMICOLON || it.node.isPartOfComment() }\n            .let { siblings ->\n                siblings\n                    .last()\n                    .node\n                    .lastLineNumber() - siblings\n                    .first()\n                    .node\n                    .getLineNumber() - 1\n            }\n\n        if (firstUsageStatementLine - numLinesToSkip != property.node.lastLineNumber() + 1 + offset) {\n            LOCAL_VARIABLE_EARLY_DECLARATION.warn(configRules, emitWarn,\n                warnMessage(property.name!!, property.node.getLineNumber(), firstUsageLine\n                    ?: firstUsageStatementLine), property.startOffset, property.node)\n        }\n    }\n\n    /**\n     * Returns the [KtBlockExpression] with which a property should be compared.\n     * If the usage is in nested block, compared to declaration, then statement from declaration scope, which contains block\n     * with usage, is returned.\n     *\n     * @return either the line on which the property is used if it is first used in the same scope, or the block in the same scope as declaration\n     */\n    @Suppress(\"UnsafeCallOnNullableType\", \"GENERIC_VARIABLE_WRONG_DECLARATION\")\n    private fun getFirstUsageStatementOrBlock(usages: List<KtNameReferenceExpression>, declarationScope: KtBlockExpression?): PsiElement {\n        val firstUsage = usages.minByOrNull { it.node.getLineNumber() }!!\n        val firstUsageScope = firstUsage.getParentOfType<KtBlockExpression>(true)\n\n        return if (firstUsageScope == declarationScope) {\n            // property is first used in the same scope where it is declared, we check line of statement where it is first used\n            firstUsage\n                .parents\n                .find { it.parent == declarationScope }!!\n        } else {\n            // first usage is in deeper block compared to declaration, need to check how close is declaration to the first line of the block\n            usages.minByOrNull { it.node.getLineNumber() }!!\n                .parentsWithSelf\n                .find { it.parent == declarationScope }!!\n        }\n    }\n\n    private fun KtCallExpression?.isWhitelistedMethod() =\n        this?.run {\n            // `referenceExpression()` can return something different than just a name, e.g. when function returns a function:\n            // `foo()()` `referenceExpression()` will be a `KtCallExpression` as well\n            (referenceExpression() as? KtNameReferenceExpression)?.getReferencedName() in functionInitializers &&\n                    valueArguments.isEmpty()\n        } ?: false\n\n    private fun warnMessage(\n        name: String,\n        declared: Int,\n        used: Int\n    ) = \"<$name> is declared on line <$declared> and is used for the first time on line <$used>\"\n\n    companion object {\n        const val NAME_ID = \"local-variables\"\n        private val functionInitializers = listOf(\n            \"emptyList\", \"emptySet\", \"emptyMap\", \"emptyArray\", \"emptySequence\",\n            \"listOf\", \"setOf\", \"mapOf\", \"arrayOf\", \"arrayListOf\",\n            \"mutableListOf\", \"mutableSetOf\", \"mutableMapOf\",\n            \"linkedMapOf\", \"linkedSetOf\"\n        )\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/main/kotlin/com/saveourtool/diktat/ruleset/rules/chapter4/ImmutableValNoVarRule.kt",
    "content": "package com.saveourtool.diktat.ruleset.rules.chapter4\n\nimport com.saveourtool.diktat.common.config.rules.RulesConfig\nimport com.saveourtool.diktat.ruleset.constants.Warnings.SAY_NO_TO_VAR\nimport com.saveourtool.diktat.ruleset.rules.DiktatRule\nimport com.saveourtool.diktat.ruleset.utils.search.findAllVariablesWithAssignments\nimport com.saveourtool.diktat.ruleset.utils.search.findAllVariablesWithUsages\n\nimport org.jetbrains.kotlin.com.intellij.lang.ASTNode\nimport org.jetbrains.kotlin.psi.KtBlockExpression\nimport org.jetbrains.kotlin.psi.KtLambdaExpression\nimport org.jetbrains.kotlin.psi.KtLoopExpression\nimport org.jetbrains.kotlin.psi.psiUtil.getParentOfType\nimport org.jetbrains.kotlin.psi.stubs.elements.KtFileElementType\n\n/**\n * Variables with `val` modifier - are immutable (read-only).\n * Usage of such variables instead of `var` variables increases robustness and readability of code,\n * because `var` variables can be reassigned several times in the business logic. Of course, in some scenarios with loops or accumulators only `var`s can be used and are allowed.\n * FixMe: here we should also raise warnings for a reassignment of a var (if var has no assignments except in declaration - it can be final)\n */\nclass ImmutableValNoVarRule(configRules: List<RulesConfig>) : DiktatRule(\n    NAME_ID,\n    configRules,\n    listOf(SAY_NO_TO_VAR)\n) {\n    override fun logic(node: ASTNode) {\n        if (node.elementType == KtFileElementType.INSTANCE) {\n            // we will raise warning for cases when var property has no assignments\n            val varNoAssignments = node\n                .findAllVariablesWithAssignments { it.name != null && it.isVar }\n                .filter { it.value.isEmpty() }\n\n            varNoAssignments.forEach { (_, _) ->\n                // FixMe: raise another warning and fix the code (change to val) for variables without assignment\n            }\n\n            // we can force to be immutable only variables that are from local context (not from class and not from file-level)\n            val usages = node\n                .findAllVariablesWithUsages { it.isLocal && it.name != null && it.parent is KtBlockExpression && it.isVar }\n                .filter { !varNoAssignments.containsKey(it.key) }\n\n            usages.forEach { (property, usages) ->\n                val usedInAccumulators = usages.any {\n                    it.getParentOfType<KtLoopExpression>(true) != null ||\n                            it.getParentOfType<KtLambdaExpression>(true) != null\n                }\n\n                if (!usedInAccumulators) {\n                    SAY_NO_TO_VAR.warn(configRules, emitWarn, property.text, property.node.startOffset, property.node)\n                }\n            }\n\n            return\n        }\n    }\n    companion object {\n        const val NAME_ID = \"no-var-rule\"\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/main/kotlin/com/saveourtool/diktat/ruleset/rules/chapter4/NullChecksRule.kt",
    "content": "package com.saveourtool.diktat.ruleset.rules.chapter4\n\nimport com.saveourtool.diktat.common.config.rules.RulesConfig\nimport com.saveourtool.diktat.ruleset.constants.Warnings.AVOID_NULL_CHECKS\nimport com.saveourtool.diktat.ruleset.rules.DiktatRule\nimport com.saveourtool.diktat.ruleset.utils.*\nimport com.saveourtool.diktat.ruleset.utils.parent\n\nimport org.jetbrains.kotlin.KtNodeTypes.BINARY_EXPRESSION\nimport org.jetbrains.kotlin.KtNodeTypes.BLOCK\nimport org.jetbrains.kotlin.KtNodeTypes.BREAK\nimport org.jetbrains.kotlin.KtNodeTypes.CALL_EXPRESSION\nimport org.jetbrains.kotlin.KtNodeTypes.CLASS_INITIALIZER\nimport org.jetbrains.kotlin.KtNodeTypes.CONDITION\nimport org.jetbrains.kotlin.KtNodeTypes.ELSE\nimport org.jetbrains.kotlin.KtNodeTypes.IF\nimport org.jetbrains.kotlin.KtNodeTypes.NULL\nimport org.jetbrains.kotlin.KtNodeTypes.REFERENCE_EXPRESSION\nimport org.jetbrains.kotlin.KtNodeTypes.THEN\nimport org.jetbrains.kotlin.KtNodeTypes.VALUE_ARGUMENT\nimport org.jetbrains.kotlin.KtNodeTypes.VALUE_ARGUMENT_LIST\nimport org.jetbrains.kotlin.com.intellij.lang.ASTNode\nimport org.jetbrains.kotlin.com.intellij.psi.tree.IElementType\nimport org.jetbrains.kotlin.lexer.KtTokens\nimport org.jetbrains.kotlin.lexer.KtTokens.IF_KEYWORD\nimport org.jetbrains.kotlin.psi.KtBinaryExpression\nimport org.jetbrains.kotlin.psi.KtBlockExpression\nimport org.jetbrains.kotlin.psi.KtIfExpression\nimport org.jetbrains.kotlin.psi.KtPsiUtil\nimport org.jetbrains.kotlin.psi.psiUtil.blockExpressionsOrSingle\nimport org.jetbrains.kotlin.psi.psiUtil.parents\n\ntypealias ThenAndElseLines = Pair<List<String>?, List<String>?>\n\n/**\n * This rule check and fixes explicit null checks (explicit comparison with `null`)\n * There are several code-structures that can be used in Kotlin to avoid null-checks. For example: `?:`,  `.let {}`, `.also {}`, e.t.c\n */\nclass NullChecksRule(configRules: List<RulesConfig>) : DiktatRule(\n    NAME_ID,\n    configRules,\n    listOf(AVOID_NULL_CHECKS)\n) {\n    override fun logic(node: ASTNode) {\n        if (node.elementType == CONDITION) {\n            node.parent(IF)?.let {\n                // excluding complex cases with else-if statements, because they look better with explicit null-check\n                if (!isComplexIfStatement(it)) {\n                    // this can be autofixed as the condition stays in simple if-statement\n                    conditionInIfStatement(node)\n                }\n            }\n        }\n\n        if (node.elementType == BINARY_EXPRESSION) {\n            // `condition` case is already checked above, so no need to check it once again\n            node.parent(CONDITION) ?: run {\n                // only warning here, because autofix in other statements (like) lambda (or value) can break the code\n                nullCheckInOtherStatements(node)\n            }\n        }\n    }\n\n    /**\n     * checks that if-statement is a complex condition\n     * You can name a statement - \"complex if-statement\" if it has other if in the else branch (else-if structure)\n     */\n    private fun isComplexIfStatement(parentIf: ASTNode): Boolean {\n        val parentIfPsi = parentIf.psi\n        require(parentIfPsi is KtIfExpression)\n        return (parentIfPsi.`else`\n            ?.node\n            ?.firstChildNode\n            ?.elementType == IF_KEYWORD)\n    }\n\n    private fun conditionInIfStatement(node: ASTNode) {\n        node.findAllDescendantsWithSpecificType(BINARY_EXPRESSION).forEach { binaryExprNode ->\n            val condition = (binaryExprNode.psi as KtBinaryExpression)\n\n            if (isNullCheckBinaryExpression(condition)) {\n                val isEqualToNull = when (condition.operationToken) {\n                    // `==` and `===` comparison can be fixed with `?:` operator\n                    KtTokens.EQEQ, KtTokens.EQEQEQ -> true\n                    // `!=` and `!==` comparison can be fixed with `.let/also` operators\n                    KtTokens.EXCLEQ, KtTokens.EXCLEQEQEQ -> false\n                    else -> return\n                }\n\n                val (_, elseCodeLines) = getThenAndElseLines(node, isEqualToNull)\n                val (numberOfStatementsInElseBlock, isAssignmentInNewElseBlock) = getInfoAboutElseBlock(node, isEqualToNull)\n\n                // if `if-else` block inside `init` or 'run', 'with', 'apply' blocks and there is more than one statement inside 'else' block, then\n                // we don't have to make any fixes, because this leads to kotlin compilation error after adding 'run' block instead of 'else' block\n                // read https://youtrack.jetbrains.com/issue/KT-64174 for more information\n                if (shouldBeWarned(node, elseCodeLines, numberOfStatementsInElseBlock, isAssignmentInNewElseBlock)) {\n                    warnAndFixOnNullCheck(\n                        condition,\n                        canBeAutoFixed(node, isEqualToNull),\n                        \"use '.let/.also/?:/e.t.c' instead of ${condition.text}\"\n                    ) {\n                        fixNullInIfCondition(node, condition, isEqualToNull)\n                    }\n                }\n            }\n        }\n    }\n\n    /**\n     * Checks whether it is necessary to warn about null-check\n     */\n    private fun shouldBeWarned(\n        condition: ASTNode,\n        elseCodeLines: List<String>?,\n        numberOfStatementsInElseBlock: Int,\n        isAssignment: Boolean,\n    ): Boolean = when {\n        // else { \"null\"/empty } -> \"\"\n        isNullOrEmptyElseBlock(elseCodeLines) -> true\n        // else { bar() } -> ?: bar()\n        isOnlyOneNonAssignmentStatementInElseBlock(numberOfStatementsInElseBlock, isAssignment) -> true\n        // else { ... } -> ?: run { ... }\n        else -> isNotInsideWrongBlock(condition)\n    }\n\n    private fun isOnlyOneNonAssignmentStatementInElseBlock(numberOfStatementsInElseBlock: Int, isAssignment: Boolean) = numberOfStatementsInElseBlock == 1 && !isAssignment\n\n    private fun isNullOrEmptyElseBlock(elseCodeLines: List<String>?) = elseCodeLines == null || elseCodeLines.singleOrNull() == \"null\"\n\n    private fun isNotInsideWrongBlock(condition: ASTNode): Boolean = condition.parents().none {\n        it.elementType == CLASS_INITIALIZER ||\n                (it.elementType == CALL_EXPRESSION &&\n                        it.findChildByType(REFERENCE_EXPRESSION)?.text in listOf(\"run\", \"with\", \"apply\"))\n    }\n\n    /**\n     * Checks whether null-check can be auto fixed\n     */\n    @Suppress(\"UnsafeCallOnNullableType\")\n    private fun canBeAutoFixed(condition: ASTNode,\n                               isEqualToNull: Boolean): Boolean {\n        // Handle cases with `break` word in blocks\n        val typePair = if (isEqualToNull) {\n            (ELSE to THEN)\n        } else {\n            (THEN to ELSE)\n        }\n        val isBlockInIfWithBreak = condition.getBreakNodeFromIf(typePair.first)\n        val isOneLineBlockInIfWithBreak = condition\n            .treeParent\n            .findChildByType(typePair.second)\n            ?.let { it.findChildByType(BLOCK) ?: it }\n            ?.let { astNode ->\n                astNode.hasChildOfType(BREAK) &&\n                        (astNode.psi as? KtBlockExpression)?.statements?.size != 1\n            } ?: false\n        return (!isBlockInIfWithBreak && !isOneLineBlockInIfWithBreak)\n    }\n\n    @Suppress(\"UnsafeCallOnNullableType\", \"TOO_LONG_FUNCTION\")\n    private fun fixNullInIfCondition(\n        condition: ASTNode,\n        binaryExpression: KtBinaryExpression,\n        isEqualToNull: Boolean\n    ) {\n        val variableName = binaryExpression.left!!.text\n        val (thenCodeLines, elseCodeLines) = getThenAndElseLines(condition, isEqualToNull)\n        val (numberOfStatementsInElseBlock, isAssignmentInNewElseBlock) = getInfoAboutElseBlock(condition, isEqualToNull)\n\n        val elseEditedCodeLines = getEditedElseCodeLines(elseCodeLines, numberOfStatementsInElseBlock, isAssignmentInNewElseBlock)\n        val thenEditedCodeLines = getEditedThenCodeLines(variableName, thenCodeLines, elseEditedCodeLines)\n\n        val newTextForReplacement = \"$thenEditedCodeLines $elseEditedCodeLines\"\n        val newNodeForReplacement = KotlinParser().createNode(newTextForReplacement)\n        val ifNode = condition.treeParent\n        ifNode.treeParent.replaceChild(ifNode, newNodeForReplacement)\n    }\n\n    private fun getThenAndElseLines(condition: ASTNode, isEqualToNull: Boolean): ThenAndElseLines {\n        val thenFromExistingCode = condition.extractLinesFromBlock(THEN)\n        val elseFromExistingCode = condition.extractLinesFromBlock(ELSE)\n\n        // if (a == null) { foo() } else { bar() } -> if (a != null) { bar() } else { foo() }\n        val thenCodeLines = if (isEqualToNull) {\n            elseFromExistingCode\n        } else {\n            thenFromExistingCode\n        }\n        val elseCodeLines = if (isEqualToNull) {\n            thenFromExistingCode\n        } else {\n            elseFromExistingCode\n        }\n\n        return Pair(thenCodeLines, elseCodeLines)\n    }\n\n    private fun getInfoAboutElseBlock(condition: ASTNode, isEqualToNull: Boolean) =\n        ((condition.treeParent.psi as? KtIfExpression)\n            ?.let {\n                if (isEqualToNull) {\n                    it.then\n                } else {\n                    it.`else`\n                }\n            }\n            ?.blockExpressionsOrSingle()\n            ?.let { elements ->\n                elements.count() to elements.any { element ->\n                    KtPsiUtil.isAssignment(element)\n                }\n            }\n            ?: Pair(0, false))\n\n    @Suppress(\"UnsafeCallOnNullableType\")\n    private fun getEditedElseCodeLines(\n        elseCodeLines: List<String>?,\n        numberOfStatementsInElseBlock: Int,\n        isAssignment: Boolean,\n    ): String = when {\n        // else { \"null\"/empty } -> \"\"\n        isNullOrEmptyElseBlock(elseCodeLines) -> \"\"\n        // else { bar() } -> ?: bar()\n        isOnlyOneNonAssignmentStatementInElseBlock(numberOfStatementsInElseBlock, isAssignment) -> \"?: ${elseCodeLines!!.joinToString(postfix = \"\\n\", separator = \"\\n\")}\"\n        // else { ... } -> ?: run { ... }\n        else -> getDefaultCaseElseCodeLines(elseCodeLines!!)\n    }\n\n    @Suppress(\"UnsafeCallOnNullableType\")\n    private fun getEditedThenCodeLines(\n        variableName: String,\n        thenCodeLines: List<String>?,\n        elseEditedCodeLines: String\n    ): String = when {\n        // if (a != null) {  } -> a ?: editedElse\n        (thenCodeLines.isNullOrEmpty() && elseEditedCodeLines.isNotEmpty()) ||\n                // if (a != null) { a } else { ... } -> a ?: editedElse\n                (thenCodeLines?.singleOrNull() == variableName && elseEditedCodeLines.isNotEmpty()) -> variableName\n        // if (a != null) { a.foo() } -> a?.foo()\n        thenCodeLines?.singleOrNull()?.startsWith(\"$variableName.\") ?: false -> \"$variableName?${thenCodeLines?.firstOrNull()!!.removePrefix(variableName)}\"\n        // if (a != null) { break } -> a?.let { ... }\n        // if (a != null) { foo() } -> a?.let { ... }\n        else -> getDefaultCaseThenCodeLines(variableName, thenCodeLines)\n    }\n\n    private fun getDefaultCaseThenCodeLines(variableName: String, thenCodeLines: List<String>?): String =\n        \"$variableName?.let {${thenCodeLines?.joinToString(prefix = \"\\n\", postfix = \"\\n\", separator = \"\\n\")}}\"\n\n    private fun getDefaultCaseElseCodeLines(elseCodeLines: List<String>): String = \"?: run {${elseCodeLines.joinToString(prefix = \"\\n\", postfix = \"\\n\", separator = \"\\n\")}}\"\n\n    @Suppress(\"COMMENT_WHITE_SPACE\", \"UnsafeCallOnNullableType\")\n    private fun nullCheckInOtherStatements(binaryExprNode: ASTNode) {\n        val condition = (binaryExprNode.psi as KtBinaryExpression)\n        if (isNullCheckBinaryExpression(condition)) {\n            // require(a != null) is incorrect, Kotlin has special method: `requireNotNull` - need to use it instead\n            // hierarchy is the following:\n            //              require(a != null)\n            //                 /            \\\n            //      REFERENCE_EXPRESSION    VALUE_ARGUMENT_LIST\n            //                |                       |\n            //          IDENTIFIER(require)     VALUE_ARGUMENT\n            val parent = binaryExprNode.treeParent\n            if (parent != null && parent.elementType == VALUE_ARGUMENT) {\n                val grandParent = parent.treeParent\n                if (grandParent != null && grandParent.elementType == VALUE_ARGUMENT_LIST && isRequireFun(grandParent.treePrev)) {\n                    @Suppress(\"COLLAPSE_IF_STATEMENTS\")\n                    if (listOf(KtTokens.EXCLEQ, KtTokens.EXCLEQEQEQ).contains(condition.operationToken)) {\n                        warnAndFixOnNullCheck(\n                            condition,\n                            true,\n                            \"use 'requireNotNull' instead of require(${condition.text})\"\n                        ) {\n                            val variableName = (binaryExprNode.psi as KtBinaryExpression).left!!.text\n                            val newMethod = KotlinParser().createNode(\"requireNotNull($variableName)\")\n                            grandParent.treeParent.treeParent.addChild(newMethod, grandParent.treeParent)\n                            grandParent.treeParent.treeParent.removeChild(grandParent.treeParent)\n                        }\n                    }\n                }\n            }\n        }\n    }\n\n    private fun ASTNode.getBreakNodeFromIf(type: IElementType) = this\n        .treeParent\n        .findChildByType(type)\n        ?.let { it.findChildByType(BLOCK) ?: it }\n        ?.findAllNodesWithCondition { it.elementType == BREAK }\n        ?.isNotEmpty()\n        ?: false\n\n    private fun ASTNode.extractLinesFromBlock(type: IElementType): List<String>? =\n        treeParent\n            .getFirstChildWithType(type)\n            ?.text\n            ?.trim('{', '}')\n            ?.split(\"\\n\")\n            ?.filter { it.isNotBlank() }\n            ?.map { it.trim() }\n            ?.toList()\n\n    @Suppress(\"UnsafeCallOnNullableType\")\n    private fun isNullCheckBinaryExpression(condition: KtBinaryExpression): Boolean =\n        // check that binary expression has `null` as right or left operand\n        setOf(condition.right, condition.left).map { it!!.node.elementType }.contains(NULL) &&\n                // checks that it is the comparison condition\n                setOf(KtTokens.EQEQ, KtTokens.EQEQEQ, KtTokens.EXCLEQ, KtTokens.EXCLEQEQEQ)\n                    .contains(condition.operationToken) &&\n                // no need to raise warning or fix null checks in complex expressions\n                !condition.isComplexCondition() &&\n                !condition.isInLambda()\n\n    /**\n     * checks if condition is a complex expression. For example:\n     * (a == 5) - is not a complex condition, but (a == 5 && b != 6) is a complex condition\n     */\n    private fun KtBinaryExpression.isComplexCondition(): Boolean {\n        // KtBinaryExpression is complex if it has a parent that is also a binary expression\n        return this.parent is KtBinaryExpression\n    }\n\n    /**\n     * Expression could be used in lambda:\n     * if (a.any { it == null })\n     */\n    private fun KtBinaryExpression.isInLambda(): Boolean {\n        // KtBinaryExpression is in lambda if it has a parent that is a block expression\n        return this.parent is KtBlockExpression\n    }\n\n    private fun warnAndFixOnNullCheck(\n        condition: KtBinaryExpression,\n        canBeAutoFixed: Boolean,\n        freeText: String,\n        autofix: () -> Unit\n    ) {\n        AVOID_NULL_CHECKS.warnOnlyOrWarnAndFix(\n            configRules,\n            emitWarn,\n            freeText,\n            condition.node.startOffset,\n            condition.node,\n            canBeAutoFixed,\n            isFixMode,\n        ) {\n            autofix()\n        }\n    }\n\n    private fun isRequireFun(referenceExpression: ASTNode) =\n        referenceExpression.elementType == REFERENCE_EXPRESSION && referenceExpression.firstChildNode.text == \"require\"\n\n    companion object {\n        const val NAME_ID = \"null-checks\"\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/main/kotlin/com/saveourtool/diktat/ruleset/rules/chapter4/SmartCastRule.kt",
    "content": "package com.saveourtool.diktat.ruleset.rules.chapter4\n\nimport com.saveourtool.diktat.common.config.rules.RulesConfig\nimport com.saveourtool.diktat.ruleset.constants.Warnings.SMART_CAST_NEEDED\nimport com.saveourtool.diktat.ruleset.rules.DiktatRule\nimport com.saveourtool.diktat.ruleset.utils.KotlinParser\nimport com.saveourtool.diktat.ruleset.utils.findAllDescendantsWithSpecificType\nimport com.saveourtool.diktat.ruleset.utils.findParentNodeWithSpecificType\nimport com.saveourtool.diktat.ruleset.utils.getFirstChildWithType\nimport com.saveourtool.diktat.ruleset.utils.hasParent\nimport com.saveourtool.diktat.ruleset.utils.search.findAllVariablesWithUsages\n\nimport org.jetbrains.kotlin.KtNodeTypes.BINARY_WITH_TYPE\nimport org.jetbrains.kotlin.KtNodeTypes.BLOCK\nimport org.jetbrains.kotlin.KtNodeTypes.DOT_QUALIFIED_EXPRESSION\nimport org.jetbrains.kotlin.KtNodeTypes.ELSE\nimport org.jetbrains.kotlin.KtNodeTypes.FLOAT_CONSTANT\nimport org.jetbrains.kotlin.KtNodeTypes.IF\nimport org.jetbrains.kotlin.KtNodeTypes.INTEGER_CONSTANT\nimport org.jetbrains.kotlin.KtNodeTypes.IS_EXPRESSION\nimport org.jetbrains.kotlin.KtNodeTypes.REFERENCE_EXPRESSION\nimport org.jetbrains.kotlin.KtNodeTypes.STRING_TEMPLATE\nimport org.jetbrains.kotlin.KtNodeTypes.THEN\nimport org.jetbrains.kotlin.KtNodeTypes.WHEN\nimport org.jetbrains.kotlin.com.intellij.lang.ASTNode\nimport org.jetbrains.kotlin.lexer.KtTokens\nimport org.jetbrains.kotlin.psi.KtBlockExpression\nimport org.jetbrains.kotlin.psi.KtNameReferenceExpression\nimport org.jetbrains.kotlin.psi.KtProperty\nimport org.jetbrains.kotlin.psi.psiUtil.isAncestor\nimport org.jetbrains.kotlin.psi.psiUtil.parents\nimport org.jetbrains.kotlin.psi.stubs.elements.KtFileElementType\n\n/**\n * Rule that detects redundant explicit casts\n */\nclass SmartCastRule(configRules: List<RulesConfig>) : DiktatRule(\n    NAME_ID,\n    configRules,\n    listOf(SMART_CAST_NEEDED)\n) {\n    override fun logic(node: ASTNode) {\n        if (node.elementType == KtFileElementType.INSTANCE) {\n            val usages = collectLocalPropertiesWithUsages(node)\n            val properMap = collectReferenceList(usages)\n            handleProp(properMap)\n        }\n\n        if (node.elementType == WHEN) {\n            // Rule is simplified after https://github.com/saveourtool/diktat/issues/1168\n            return\n        }\n    }\n\n    // Divide in is and as expr\n    @Suppress(\"TYPE_ALIAS\")\n    private fun handleProp(propMap: Map<KtProperty, List<KtNameReferenceExpression>>) {\n        propMap.forEach { (property, references) ->\n            val isExpr: MutableList<KtNameReferenceExpression> = mutableListOf()\n            val asExpr: MutableList<KtNameReferenceExpression> = mutableListOf()\n            references.forEach {\n                if (it.node.hasParent(IS_EXPRESSION)) {\n                    isExpr.add(it)\n                } else if (it.node.hasParent(BINARY_WITH_TYPE) && it.node.treeParent.text.contains(KtTokens.AS_KEYWORD.value)) {\n                    asExpr.add(it)\n                }\n            }\n            val groups = groupIsAndAsExpr(isExpr, asExpr, property)\n            if (groups.isNotEmpty()) {\n                handleGroups(groups)\n            }\n        }\n    }\n\n    /**\n     * If condition == is then we are looking for then block\n     * If condition == !is then we are looking for else block\n     */\n    @Suppress(\"NestedBlockDepth\", \"TYPE_ALIAS\")\n    private fun handleGroups(groups: Map<KtNameReferenceExpression, List<KtNameReferenceExpression>>) {\n        groups.keys.forEach { key ->\n            val parentText = key.node.treeParent.text\n            if (parentText.contains(\" is \")) {\n                groups.getValue(key).forEach { asCall ->\n                    if (asCall.node.hasParent(THEN)) {\n                        raiseWarning(asCall.node)\n                    }\n                }\n            } else if (parentText.contains(\" !is \")) {\n                groups.getValue(key).forEach { asCall ->\n                    if (asCall.node.hasParent(ELSE)) {\n                        raiseWarning(asCall.node)\n                    }\n                }\n            }\n        }\n    }\n\n    @Suppress(\"UnsafeCallOnNullableType\")\n    private fun raiseWarning(asCall: ASTNode) {\n        SMART_CAST_NEEDED.warnAndFix(configRules, emitWarn, isFixMode, asCall.treeParent.text, asCall.startOffset,\n            asCall) {\n            val dotExpr = asCall.findParentNodeWithSpecificType(DOT_QUALIFIED_EXPRESSION)\n            val afterDotPart = dotExpr?.text?.split(\".\")?.get(1)\n            val text = afterDotPart?.let { \"${asCall.text}.$afterDotPart\" } ?: asCall.text\n            (dotExpr ?: asCall.treeParent).treeParent.addChild(KotlinParser().createNode(text), (dotExpr ?: asCall.treeParent))\n            (dotExpr ?: asCall.treeParent).treeParent.removeChild((dotExpr ?: asCall.treeParent))\n        }\n    }\n\n    /**\n     * Groups is and as expressions, so that they are used in same if block\n     */\n    @Suppress(\"TYPE_ALIAS\")\n    private fun groupIsAndAsExpr(isExpr: List<KtNameReferenceExpression>,\n                                 asExpr: List<KtNameReferenceExpression>,\n                                 prop: KtProperty\n    ): Map<KtNameReferenceExpression, List<KtNameReferenceExpression>> {\n        if (isExpr.isEmpty() && asExpr.isNotEmpty()) {\n            handleZeroIsCase(asExpr, prop)\n            return emptyMap()\n        }\n\n        val groupedExprs: MutableMap<KtNameReferenceExpression, List<KtNameReferenceExpression>> = mutableMapOf()\n        isExpr.forEach { ref ->\n            val list: MutableList<KtNameReferenceExpression> = mutableListOf()\n            asExpr.forEach { asCall ->\n                if (asCall.node.findParentNodeWithSpecificType(IF)\n                        == ref.node.findParentNodeWithSpecificType(IF)) {\n                    list.add(asCall)\n                }\n            }\n            groupedExprs[ref] = list\n        }\n        return groupedExprs\n    }\n\n    @Suppress(\"UnsafeCallOnNullableType\")\n    private fun getPropertyType(prop: KtProperty): String? {\n        when (prop.initializer?.node?.elementType) {\n            STRING_TEMPLATE -> return \"String\"\n            INTEGER_CONSTANT -> return \"Int\"\n            else -> {\n            }\n        }\n        if (prop.initializer?.node?.elementType == FLOAT_CONSTANT) {\n            if (prop.initializer?.text!!.endsWith(\"f\")) {\n                return \"Float\"\n            }\n            return \"Double\"\n        }\n        return null\n    }\n\n    @Suppress(\"UnsafeCallOnNullableType\")\n    private fun handleZeroIsCase(asExpr: List<KtNameReferenceExpression>, prop: KtProperty) {\n        val propType = getPropertyType(prop) ?: return\n        asExpr\n            .map { it.node }\n            .forEach {\n                if (it.treeParent.text.endsWith(propType)) {\n                    raiseWarning(it)\n                }\n            }\n    }\n\n    private fun handleThenBlock(then: ASTNode, blocks: List<IsExpressions>) {\n        val thenBlock = then.findChildByType(BLOCK)\n\n        thenBlock?.let {\n            // Find all as expressions that are inside this current block\n            val asList = thenBlock\n                .findAllDescendantsWithSpecificType(BINARY_WITH_TYPE)\n                .filter {\n                    it.text.contains(\" as \") && it.findParentNodeWithSpecificType(BLOCK) == thenBlock\n                }\n                .filterNot { (it.getFirstChildWithType(REFERENCE_EXPRESSION)?.psi as KtNameReferenceExpression).getLocalDeclaration() != null }\n            checkAsExpressions(asList, blocks)\n        }\n            ?: run {\n                val asList = then.findAllDescendantsWithSpecificType(BINARY_WITH_TYPE).filter { it.text.contains(KtTokens.AS_KEYWORD.value) }\n                checkAsExpressions(asList, blocks)\n            }\n    }\n\n    @Suppress(\"UnsafeCallOnNullableType\")\n    private fun checkAsExpressions(asList: List<ASTNode>, blocks: List<IsExpressions>) {\n        val asExpr: MutableList<AsExpressions> = mutableListOf()\n\n        @Suppress(\"PARAMETER_NAME_IN_OUTER_LAMBDA\")\n        asList.forEach {\n            val split = it.text.split(\"as\").map { part -> part.trim() }\n            asExpr.add(AsExpressions(split[0], split[1], it))\n        }\n\n        val exprToChange = asExpr.filter { asCall ->\n            blocks.any { isExpr ->\n                isExpr.identifier == asCall.identifier &&\n                        isExpr.type == asCall.type\n            }\n        }\n\n        if (exprToChange.isNotEmpty()) {\n            exprToChange.forEach { asCall ->\n                SMART_CAST_NEEDED.warnAndFix(configRules, emitWarn, isFixMode, \"${asCall.identifier} as ${asCall.type}\", asCall.node.startOffset,\n                    asCall.node) {\n                    val dotExpr = asCall.node.findParentNodeWithSpecificType(DOT_QUALIFIED_EXPRESSION)!!\n                    val afterDotPart = dotExpr.text.split(\".\")[1]\n                    val text = \"${asCall.identifier}.$afterDotPart\"\n                    dotExpr.treeParent.addChild(KotlinParser().createNode(text), dotExpr)\n                    dotExpr.treeParent.removeChild(dotExpr)\n                }\n            }\n        }\n    }\n\n    private fun KtNameReferenceExpression.getLocalDeclaration(): KtProperty? = parents\n        .mapNotNull { it as? KtBlockExpression }\n        .first()\n        .let { blockExpression ->\n            blockExpression\n                .statements\n                .takeWhile { !it.isAncestor(this, true) }\n                .mapNotNull { it as? KtProperty }\n                .find {\n                    it.isLocal &&\n                            it.hasInitializer() &&\n                            it.name?.equals(getReferencedName())\n                            ?: false\n                }\n        }\n\n    private fun collectLocalPropertiesWithUsages(node: ASTNode) = node\n        .findAllVariablesWithUsages { propertyNode ->\n            propertyNode.name != null\n        }\n\n    /**\n     * Gets references, which contains is or as keywords\n     *\n     * @return Map of property and list of expressions\n     */\n    @Suppress(\"TYPE_ALIAS\")\n    private fun collectReferenceList(propertiesToUsages: Map<KtProperty, List<KtNameReferenceExpression>>): Map<KtProperty, List<KtNameReferenceExpression>> =\n        propertiesToUsages.mapValues { (_, value) ->\n            value.filter { entry ->\n                entry.parent.node.elementType == IS_EXPRESSION || entry.parent.node.elementType == BINARY_WITH_TYPE\n            }\n        }\n\n    /**\n     * @property identifier a reference that is cast\n     * @property type a type to which the reference is being cast\n     * @property node a node that holds the entire expression\n     */\n    data class AsExpressions(\n        val identifier: String,\n        val type: String,\n        val node: ASTNode\n    )\n\n    /**\n     * @property identifier a reference that is checked\n     * @property type a type with which the reference is being compared\n     */\n    data class IsExpressions(val identifier: String, val type: String)\n\n    companion object {\n        const val NAME_ID = \"smart-cast-rule\"\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/main/kotlin/com/saveourtool/diktat/ruleset/rules/chapter4/TypeAliasRule.kt",
    "content": "package com.saveourtool.diktat.ruleset.rules.chapter4\n\nimport com.saveourtool.diktat.common.config.rules.RuleConfiguration\nimport com.saveourtool.diktat.common.config.rules.RulesConfig\nimport com.saveourtool.diktat.common.config.rules.getRuleConfig\nimport com.saveourtool.diktat.ruleset.constants.Warnings.TYPE_ALIAS\nimport com.saveourtool.diktat.ruleset.rules.DiktatRule\nimport com.saveourtool.diktat.ruleset.utils.*\n\nimport org.jetbrains.kotlin.KtNodeTypes.SUPER_TYPE_LIST\nimport org.jetbrains.kotlin.KtNodeTypes.TYPEALIAS\nimport org.jetbrains.kotlin.KtNodeTypes.TYPE_REFERENCE\nimport org.jetbrains.kotlin.KtNodeTypes.VALUE_PARAMETER\nimport org.jetbrains.kotlin.com.intellij.lang.ASTNode\nimport org.jetbrains.kotlin.lexer.KtTokens.LT\nimport org.jetbrains.kotlin.psi.psiUtil.parents\n\n/**\n * This rule checks if variable has long type reference and two or more nested generics.\n * Length type reference can be configured\n */\nclass TypeAliasRule(configRules: List<RulesConfig>) : DiktatRule(\n    NAME_ID,\n    configRules,\n    listOf(TYPE_ALIAS)\n) {\n    override fun logic(node: ASTNode) {\n        if (node.elementType == TYPE_REFERENCE && node\n            .parents()\n            .map { it.elementType }\n            .none { it == SUPER_TYPE_LIST || it == TYPEALIAS }) {\n            checkTypeReference(node, TypeAliasConfiguration(configRules.getRuleConfig(TYPE_ALIAS)?.configuration ?: emptyMap()))\n        }\n    }\n\n    /**\n     * Check properties for nested generics. Count LT for generic types and VALUE_PARAMETER for functional types\n     */\n    private fun checkTypeReference(node: ASTNode, config: TypeAliasConfiguration) {\n        if (node.textLength > config.typeReferenceLength) {\n            @Suppress(\"COLLAPSE_IF_STATEMENTS\")\n            if (node.findAllDescendantsWithSpecificType(LT).size > 1 || node.findAllDescendantsWithSpecificType(VALUE_PARAMETER).size > 1) {\n                TYPE_ALIAS.warn(configRules, emitWarn, \"too long type reference\", node.startOffset, node)\n            }\n        }\n    }\n\n    /**\n     * [RuleConfiguration] about using type aliases instead of complex types\n     */\n    class TypeAliasConfiguration(config: Map<String, String>) : RuleConfiguration(config) {\n        /**\n         * Maximum length of a type before suggesting to use typealias\n         */\n        val typeReferenceLength = config[\"typeReferenceLength\"]?.toIntOrNull() ?: TYPE_REFERENCE_MAX_LENGTH\n    }\n\n    companion object {\n        const val NAME_ID = \"type-alias\"\n        const val TYPE_REFERENCE_MAX_LENGTH = 25\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/main/kotlin/com/saveourtool/diktat/ruleset/rules/chapter4/VariableGenericTypeDeclarationRule.kt",
    "content": "package com.saveourtool.diktat.ruleset.rules.chapter4\n\nimport com.saveourtool.diktat.common.config.rules.RulesConfig\nimport com.saveourtool.diktat.ruleset.constants.Warnings.GENERIC_VARIABLE_WRONG_DECLARATION\nimport com.saveourtool.diktat.ruleset.rules.DiktatRule\nimport com.saveourtool.diktat.ruleset.utils.getAllChildrenWithType\n\nimport org.jetbrains.kotlin.KtNodeTypes.CALL_EXPRESSION\nimport org.jetbrains.kotlin.KtNodeTypes.DOT_QUALIFIED_EXPRESSION\nimport org.jetbrains.kotlin.KtNodeTypes.PROPERTY\nimport org.jetbrains.kotlin.KtNodeTypes.TYPE_ARGUMENT_LIST\nimport org.jetbrains.kotlin.KtNodeTypes.VALUE_PARAMETER\nimport org.jetbrains.kotlin.com.intellij.lang.ASTNode\nimport org.jetbrains.kotlin.psi.KtCallExpression\nimport org.jetbrains.kotlin.psi.KtParameter\nimport org.jetbrains.kotlin.psi.KtProperty\n\n/**\n * This Rule checks if declaration of a generic variable is appropriate.\n * Not recommended: val myVariable: Map<Int, String> = emptyMap<Int, String>() or val myVariable = emptyMap<Int, String>()\n * Recommended: val myVariable: Map<Int, String> = emptyMap()\n */\n@Suppress(\"ForbiddenComment\")\n// FIXME: we now don't have access to return types, so we can perform this check only if explicit type is present, but should be able also if it's not.\nclass VariableGenericTypeDeclarationRule(configRules: List<RulesConfig>) : DiktatRule(\n    NAME_ID,\n    configRules,\n    listOf(GENERIC_VARIABLE_WRONG_DECLARATION)\n) {\n    override fun logic(node: ASTNode) {\n        when (node.elementType) {\n            PROPERTY, VALUE_PARAMETER -> handleProperty(node)\n            else -> {\n            }\n        }\n    }\n\n    @Suppress(\"UnsafeCallOnNullableType\", \"AVOID_NULL_CHECKS\")\n    private fun handleProperty(node: ASTNode) {\n        val callExpr = node.findChildByType(CALL_EXPRESSION)\n            ?: node\n                .findChildByType(DOT_QUALIFIED_EXPRESSION)\n                ?.getAllChildrenWithType(CALL_EXPRESSION)\n                ?.lastOrNull()\n\n        val rightSide = (callExpr?.psi as? KtCallExpression)?.typeArgumentList?.arguments\n        val leftSide = if (node.elementType == PROPERTY) {\n            (node.psi as? KtProperty)\n                ?.typeReference\n                ?.typeElement\n                ?.typeArgumentsAsTypes\n        } else {\n            (node.psi as? KtParameter)\n                ?.typeReference\n                ?.typeElement\n                ?.typeArgumentsAsTypes\n        }\n\n        // Allow cases with wild card types; `*` interprets as `null` in list of types\n        if (leftSide?.any { it == null } == true) {\n            return\n        }\n\n        if (rightSide != null && leftSide != null &&\n                rightSide.size == leftSide.size &&\n                rightSide.zip(leftSide).all { (first, second) -> first.text == second.text }) {\n            GENERIC_VARIABLE_WRONG_DECLARATION.warnAndFix(configRules, emitWarn, isFixMode,\n                \"type arguments are unnecessary in ${callExpr.text}\", node.startOffset, node) {\n                callExpr.removeChild(callExpr.findChildByType(TYPE_ARGUMENT_LIST)!!)\n            }\n        }\n\n        if (leftSide == null && rightSide != null) {\n            GENERIC_VARIABLE_WRONG_DECLARATION.warn(configRules, emitWarn, node.text, node.startOffset, node)\n        }\n    }\n\n    companion object {\n        const val NAME_ID = \"variable-generic-type\"\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/main/kotlin/com/saveourtool/diktat/ruleset/rules/chapter4/calculations/AccurateCalculationsRule.kt",
    "content": "package com.saveourtool.diktat.ruleset.rules.chapter4.calculations\n\nimport com.saveourtool.diktat.common.config.rules.RulesConfig\nimport com.saveourtool.diktat.ruleset.constants.Warnings.FLOAT_IN_ACCURATE_CALCULATIONS\nimport com.saveourtool.diktat.ruleset.rules.DiktatRule\nimport com.saveourtool.diktat.ruleset.utils.findLocalDeclaration\nimport com.saveourtool.diktat.ruleset.utils.getFunctionName\n\nimport org.jetbrains.kotlin.KtNodeTypes\nimport org.jetbrains.kotlin.com.intellij.lang.ASTNode\nimport org.jetbrains.kotlin.com.intellij.psi.PsiElement\nimport org.jetbrains.kotlin.lexer.KtTokens\nimport org.jetbrains.kotlin.psi.KtBinaryExpression\nimport org.jetbrains.kotlin.psi.KtCallExpression\nimport org.jetbrains.kotlin.psi.KtDotQualifiedExpression\nimport org.jetbrains.kotlin.psi.KtExpression\nimport org.jetbrains.kotlin.psi.KtNameReferenceExpression\nimport org.jetbrains.kotlin.psi.psiUtil.parentsWithSelf\nimport org.jetbrains.kotlin.psi.psiUtil.startOffset\n\n/**\n * Rule that checks that floating-point numbers are not used for accurate calculations\n * 1. Checks that floating-point numbers are not used in arithmetic binary expressions\n *    Exception: allows arithmetic operations only when absolute value of result is immediately used in comparison\n * Fixme: detect variables by type, not only floating-point literals\n */\nclass AccurateCalculationsRule(configRules: List<RulesConfig>) : DiktatRule(\n    NAME_ID,\n    configRules,\n    listOf(FLOAT_IN_ACCURATE_CALCULATIONS)\n) {\n    private fun KtCallExpression?.isAbsOfFloat() = this\n        ?.run {\n            (calleeExpression as? KtNameReferenceExpression)\n                ?.getReferencedName()\n                ?.equals(\"abs\")\n                ?.and(\n                    valueArguments\n                        .singleOrNull()\n                        ?.getArgumentExpression()\n                        ?.isFloatingPoint()\n                        ?: false)\n                ?: false\n        }\n        ?: false\n\n    @Suppress(\"PARAMETER_NAME_IN_OUTER_LAMBDA\")\n    private fun KtDotQualifiedExpression.isComparisonWithAbs() =\n        takeIf {\n            it.selectorExpression.run {\n                this is KtCallExpression && getFunctionName() in comparisonFunctions\n            }\n        }\n            ?.run {\n                (selectorExpression as KtCallExpression)\n                    .valueArguments\n                    .singleOrNull()\n                    ?.let { it.getArgumentExpression() as? KtCallExpression }\n                    ?.isAbsOfFloat()\n                ?: false ||\n                        (receiverExpression as? KtCallExpression).isAbsOfFloat()\n            }\n            ?: false\n\n    private fun KtBinaryExpression.isComparisonWithAbs() =\n        takeIf { it.operationToken in comparisonOperators }\n            ?.run { left as? KtCallExpression ?: right as? KtCallExpression }\n            ?.run { calleeExpression as? KtNameReferenceExpression }\n            ?.getReferencedName()\n            ?.equals(\"abs\")\n            ?: false\n\n    private fun isComparisonWithAbs(psiElement: PsiElement) =\n        when (psiElement) {\n            is KtBinaryExpression -> psiElement.isComparisonWithAbs()\n            is KtDotQualifiedExpression -> psiElement.isComparisonWithAbs()\n            else -> false\n        }\n\n    private fun checkFloatValue(floatValue: PsiElement?, expression: KtExpression) {\n        floatValue?.let {\n            // float value is used in comparison\n            FLOAT_IN_ACCURATE_CALCULATIONS.warn(configRules, emitWarn,\n                \"float value of <${it.text}> used in arithmetic expression in ${expression.text}\", expression.startOffset, expression.node)\n        }\n    }\n\n    private fun handleFunction(expression: KtDotQualifiedExpression) = expression\n        .takeIf { it.selectorExpression is KtCallExpression }\n        ?.run { receiverExpression to selectorExpression as KtCallExpression }\n        ?.takeIf { it.second.getFunctionName() in arithmeticOperationsFunctions }\n        ?.takeUnless { expression.parentsWithSelf.any(::isComparisonWithAbs) }\n        ?.let { (receiverExpression, selectorExpression) ->\n            val floatValue = receiverExpression.takeIf { it.isFloatingPoint() }\n                ?: selectorExpression\n                    .valueArguments\n                    .find { it.getArgumentExpression()?.isFloatingPoint() ?: false }\n\n            checkFloatValue(floatValue, expression)\n        }\n\n    @Suppress(\"UnsafeCallOnNullableType\")\n    private fun handleBinaryExpression(expression: KtBinaryExpression) = expression\n        .takeIf { it.operationToken in arithmeticOperationTokens }\n        ?.takeUnless { it.parentsWithSelf.any(::isComparisonWithAbs) }\n        ?.run {\n            // !! is safe because `KtBinaryExpression#left` is annotated `Nullable IfNotParsed`\n            val floatValue = left!!.takeIf { it.isFloatingPoint() }\n                ?: right!!.takeIf { it.isFloatingPoint() }\n            checkFloatValue(floatValue, this)\n        }\n\n    /**\n     * @param node\n     */\n    override fun logic(node: ASTNode) {\n        when (val psi = node.psi) {\n            is KtBinaryExpression -> handleBinaryExpression(psi)\n            is KtDotQualifiedExpression -> handleFunction(psi)\n            else -> return\n        }\n    }\n\n    companion object {\n        const val NAME_ID = \"accurate-calculations\"\n        private val arithmeticOperationTokens = listOf(KtTokens.PLUS, KtTokens.PLUSEQ, KtTokens.PLUSPLUS,\n            KtTokens.MINUS, KtTokens.MINUSEQ, KtTokens.MINUSMINUS,\n            KtTokens.MUL, KtTokens.MULTEQ, KtTokens.DIV, KtTokens.DIVEQ,\n            KtTokens.PERC, KtTokens.PERCEQ,\n            KtTokens.GT, KtTokens.LT, KtTokens.LTEQ, KtTokens.GTEQ,\n            KtTokens.EQEQ\n        )\n        private val comparisonOperators = listOf(KtTokens.LT, KtTokens.LTEQ, KtTokens.GT, KtTokens.GTEQ)\n        private val arithmeticOperationsFunctions = listOf(\"equals\", \"compareTo\")\n        private val comparisonFunctions = listOf(\"compareTo\")\n    }\n}\n\n@Suppress(\"UnsafeCallOnNullableType\")\nprivate fun PsiElement.isFloatingPoint(): Boolean =\n    node.elementType == KtTokens.FLOAT_LITERAL ||\n            node.elementType == KtNodeTypes.FLOAT_CONSTANT ||\n            ((this as? KtNameReferenceExpression)\n                ?.findLocalDeclaration()\n                ?.initializer\n                ?.node\n                ?.run { elementType == KtTokens.FLOAT_LITERAL || elementType == KtNodeTypes.FLOAT_CONSTANT }\n                ?: false) ||\n            ((this as? KtBinaryExpression)\n                ?.run { left!!.isFloatingPoint() && right!!.isFloatingPoint() }\n                ?: false)\n"
  },
  {
    "path": "diktat-rules/src/main/kotlin/com/saveourtool/diktat/ruleset/rules/chapter5/AsyncAndSyncRule.kt",
    "content": "package com.saveourtool.diktat.ruleset.rules.chapter5\n\nimport com.saveourtool.diktat.common.config.rules.RulesConfig\nimport com.saveourtool.diktat.ruleset.constants.Warnings.RUN_BLOCKING_INSIDE_ASYNC\nimport com.saveourtool.diktat.ruleset.rules.DiktatRule\nimport com.saveourtool.diktat.ruleset.utils.hasChildOfType\nimport com.saveourtool.diktat.ruleset.utils.parent\n\nimport org.jetbrains.kotlin.KtNodeTypes.CALL_EXPRESSION\nimport org.jetbrains.kotlin.KtNodeTypes.FUN\nimport org.jetbrains.kotlin.KtNodeTypes.LAMBDA_ARGUMENT\nimport org.jetbrains.kotlin.KtNodeTypes.REFERENCE_EXPRESSION\nimport org.jetbrains.kotlin.com.intellij.lang.ASTNode\nimport org.jetbrains.kotlin.psi.KtFunction\nimport org.jetbrains.kotlin.psi.psiUtil.hasSuspendModifier\n\n/**\n * This rule finds if using runBlocking in asynchronous code\n */\nclass AsyncAndSyncRule(configRules: List<RulesConfig>) : DiktatRule(\n    NAME_ID,\n    configRules,\n    listOf(RUN_BLOCKING_INSIDE_ASYNC)\n) {\n    private val asyncList = listOf(\"async\", \"launch\")\n\n    override fun logic(node: ASTNode) {\n        if (node.isRunBlocking()) {\n            checkRunBlocking(node)\n        }\n    }\n\n    private fun checkRunBlocking(node: ASTNode) {\n        node.parent { it.isAsync() || it.isSuspend() }?.let {\n            RUN_BLOCKING_INSIDE_ASYNC.warn(configRules, emitWarn, node.text, node.startOffset, node)\n        }\n    }\n\n    private fun ASTNode.isAsync() = this.elementType == CALL_EXPRESSION && this.findChildByType(REFERENCE_EXPRESSION)?.text in asyncList\n\n    private fun ASTNode.isSuspend() = this.elementType == FUN && (this.psi as KtFunction).modifierList?.hasSuspendModifier() ?: false\n\n    private fun ASTNode.isRunBlocking() = this.elementType == REFERENCE_EXPRESSION && this.text == \"runBlocking\" && this.treeParent.hasChildOfType(LAMBDA_ARGUMENT)\n\n    companion object {\n        const val NAME_ID = \"sync-in-async\"\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/main/kotlin/com/saveourtool/diktat/ruleset/rules/chapter5/AvoidNestedFunctionsRule.kt",
    "content": "package com.saveourtool.diktat.ruleset.rules.chapter5\n\nimport com.saveourtool.diktat.common.config.rules.RulesConfig\nimport com.saveourtool.diktat.ruleset.constants.Warnings.AVOID_NESTED_FUNCTIONS\nimport com.saveourtool.diktat.ruleset.rules.DiktatRule\nimport com.saveourtool.diktat.ruleset.utils.findAllDescendantsWithSpecificType\nimport com.saveourtool.diktat.ruleset.utils.getFirstChildWithType\nimport com.saveourtool.diktat.ruleset.utils.hasChildOfType\nimport com.saveourtool.diktat.ruleset.utils.hasParent\nimport com.saveourtool.diktat.ruleset.utils.isAnonymousFunction\nimport com.saveourtool.diktat.ruleset.utils.isWhiteSpaceWithNewline\n\nimport org.jetbrains.kotlin.KtNodeTypes.CLASS_BODY\nimport org.jetbrains.kotlin.KtNodeTypes.FUN\nimport org.jetbrains.kotlin.KtNodeTypes.MODIFIER_LIST\nimport org.jetbrains.kotlin.KtNodeTypes.PROPERTY\nimport org.jetbrains.kotlin.KtNodeTypes.REFERENCE_EXPRESSION\nimport org.jetbrains.kotlin.com.intellij.lang.ASTNode\nimport org.jetbrains.kotlin.com.intellij.psi.impl.source.tree.PsiWhiteSpaceImpl\nimport org.jetbrains.kotlin.com.intellij.psi.tree.IElementType\nimport org.jetbrains.kotlin.lexer.KtTokens.IDENTIFIER\nimport org.jetbrains.kotlin.psi.KtFunction\nimport org.jetbrains.kotlin.psi.psiUtil.parents\n\n/**\n * This rule checks for nested functions and warns if it finds any.\n */\nclass AvoidNestedFunctionsRule(configRules: List<RulesConfig>) : DiktatRule(\n    NAME_ID,\n    configRules,\n    listOf(AVOID_NESTED_FUNCTIONS)\n) {\n    override fun logic(node: ASTNode) {\n        if (node.elementType == FUN) {\n            handleNestedFunctions(node)\n        }\n    }\n\n    // FixMe: need to detect all properties, which local function is using and add them to params of this function\n    @Suppress(\"UnsafeCallOnNullableType\")\n    private fun handleNestedFunctions(node: ASTNode) {\n        if (isNestedFunction(node)) {\n            val funcName = node.getFirstChildWithType(IDENTIFIER)!!.text\n\n            AVOID_NESTED_FUNCTIONS.warnOnlyOrWarnAndFix(configRules, emitWarn, \"fun $funcName\", node.startOffset, node,\n                shouldBeAutoCorrected = checkFunctionReferences(node), isFixMode) {\n                // We take last nested function, then add and remove child from bottom to top\n                val lastFunc = node.findAllDescendantsWithSpecificType(FUN).last()\n                val funcSeq = lastFunc\n                    .parents()\n                    .filter { it.elementType == FUN }\n                    .toMutableList()\n                funcSeq.add(0, lastFunc)\n                val firstFunc = funcSeq.last()\n                funcSeq.dropLast(1).forEachIndexed { index, it ->\n                    val parent = funcSeq[index + 1]\n                    if (it.treePrev.isWhiteSpaceWithNewline()) {\n                        parent.removeChild(it.treePrev)\n                    }\n                    firstFunc.treeParent.addChild(it.clone() as ASTNode, firstFunc)\n                    firstFunc.treeParent.addChild(PsiWhiteSpaceImpl(\"\\n\"), firstFunc)\n                    parent.removeChild(it)\n                }\n            }\n        }\n    }\n\n    private fun isNestedFunction(node: ASTNode): Boolean =\n        node.hasParent(FUN) && node.hasFunParentUntil(CLASS_BODY) && !node.hasChildOfType(MODIFIER_LIST) &&\n                !node.isAnonymousFunction()\n\n    private fun ASTNode.hasFunParentUntil(stopNode: IElementType): Boolean =\n        parents()\n            .asSequence()\n            .takeWhile { it.elementType != stopNode }\n            .any { it.elementType == FUN }\n\n    /**\n     * Checks if local function has no usage of outside properties\n     */\n    @Suppress(\"UnsafeCallOnNullableType\", \"FUNCTION_BOOLEAN_PREFIX\")\n    private fun checkFunctionReferences(func: ASTNode): Boolean {\n        val localProperties: MutableList<ASTNode> = mutableListOf()\n        localProperties.addAll(func.findAllDescendantsWithSpecificType(PROPERTY))\n        val propertiesNames: List<String> = mutableListOf<String>().apply {\n            addAll(localProperties.map { it.getFirstChildWithType(IDENTIFIER)!!.text })\n            addAll(getParameterNames(func))\n        }\n            .toList()\n\n        return func.findAllDescendantsWithSpecificType(REFERENCE_EXPRESSION).all { propertiesNames.contains(it.text) }\n    }\n\n    /**\n     * Collects all function parameters' names\n     *\n     * @return List of names\n     */\n    @Suppress(\"UnsafeCallOnNullableType\")\n    private fun getParameterNames(node: ASTNode): List<String> =\n        (node.psi as KtFunction).valueParameters.map { it.name!! }\n\n    companion object {\n        const val NAME_ID = \"avoid-nested-functions\"\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/main/kotlin/com/saveourtool/diktat/ruleset/rules/chapter5/CheckInverseMethodRule.kt",
    "content": "package com.saveourtool.diktat.ruleset.rules.chapter5\n\nimport com.saveourtool.diktat.common.config.rules.RulesConfig\nimport com.saveourtool.diktat.ruleset.constants.Warnings.INVERSE_FUNCTION_PREFERRED\nimport com.saveourtool.diktat.ruleset.rules.DiktatRule\n\nimport org.jetbrains.kotlin.KtNodeTypes.CALL_EXPRESSION\nimport org.jetbrains.kotlin.KtNodeTypes.OPERATION_REFERENCE\nimport org.jetbrains.kotlin.KtNodeTypes.REFERENCE_EXPRESSION\nimport org.jetbrains.kotlin.KtNodeTypes.VALUE_ARGUMENT_LIST\nimport org.jetbrains.kotlin.com.intellij.lang.ASTNode\nimport org.jetbrains.kotlin.com.intellij.psi.impl.source.tree.CompositeElement\nimport org.jetbrains.kotlin.com.intellij.psi.impl.source.tree.LeafPsiElement\nimport org.jetbrains.kotlin.lexer.KtTokens.BLOCK_COMMENT\nimport org.jetbrains.kotlin.lexer.KtTokens.IDENTIFIER\nimport org.jetbrains.kotlin.lexer.KtTokens.LPAR\nimport org.jetbrains.kotlin.lexer.KtTokens.RPAR\nimport org.jetbrains.kotlin.lexer.KtTokens.WHITE_SPACE\nimport org.jetbrains.kotlin.psi.psiUtil.siblings\n\n/**\n * This rule checks if inverse method can be used.\n * For example if there is !isEmpty() on collection call that it changes it to isNotEmpty()\n */\nclass CheckInverseMethodRule(configRules: List<RulesConfig>) : DiktatRule(\n    NAME_ID,\n    configRules,\n    listOf(INVERSE_FUNCTION_PREFERRED)\n) {\n    override fun logic(node: ASTNode) {\n        if (node.elementType == CALL_EXPRESSION && node.text in methodMap.keys) {\n            checkCallExpressionName(node)\n        }\n    }\n\n    private fun checkCallExpressionName(node: ASTNode) {\n        val operationRef = node\n            .treeParent\n            .siblings(forward = false)\n            .takeWhile { it.elementType in intermediateTokens }\n            .firstOrNull { it.elementType == OPERATION_REFERENCE }\n        if (operationRef?.text == \"!\") {\n            INVERSE_FUNCTION_PREFERRED.warnAndFix(configRules, emitWarn, isFixMode, \"${methodMap[node.text]} instead of !${node.text}\", node.startOffset, node) {\n                val callExpression = CompositeElement(CALL_EXPRESSION)\n                val referenceExp = CompositeElement(REFERENCE_EXPRESSION)\n                val argList = CompositeElement(VALUE_ARGUMENT_LIST)\n                node.treeParent.addChild(callExpression, node)\n                callExpression.addChild(referenceExp)\n                callExpression.addChild(argList)\n                referenceExp.addChild(LeafPsiElement(IDENTIFIER, \"${methodMap[node.text]}\".dropLast(2)))\n                argList.addChild(LeafPsiElement(LPAR, \"(\"))\n                argList.addChild(LeafPsiElement(RPAR, \")\"))\n                node.treeParent.treeParent.removeChild(node.treeParent.treePrev)  // removing OPERATION_EXPRESSION - !\n                node.treeParent.removeChild(node)\n            }\n        }\n    }\n\n    companion object {\n        const val NAME_ID = \"inverse-method\"\n        val methodMap = mapOf(\n            \"isEmpty()\" to \"isNotEmpty()\",\n            \"isBlank()\" to \"isNotBlank()\",\n            \"isNotEmpty()\" to \"isEmpty()\",\n            \"isNotBlank()\" to \"isBlank()\"\n        )\n        val intermediateTokens = listOf(WHITE_SPACE, OPERATION_REFERENCE, BLOCK_COMMENT)\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/main/kotlin/com/saveourtool/diktat/ruleset/rules/chapter5/CustomLabel.kt",
    "content": "package com.saveourtool.diktat.ruleset.rules.chapter5\n\nimport com.saveourtool.diktat.common.config.rules.RulesConfig\nimport com.saveourtool.diktat.ruleset.constants.Warnings.CUSTOM_LABEL\nimport com.saveourtool.diktat.ruleset.rules.DiktatRule\nimport com.saveourtool.diktat.ruleset.utils.loopType\n\nimport org.jetbrains.kotlin.KtNodeTypes.BREAK\nimport org.jetbrains.kotlin.KtNodeTypes.CALL_EXPRESSION\nimport org.jetbrains.kotlin.KtNodeTypes.CONTINUE\nimport org.jetbrains.kotlin.KtNodeTypes.LABEL_QUALIFIER\nimport org.jetbrains.kotlin.KtNodeTypes.REFERENCE_EXPRESSION\nimport org.jetbrains.kotlin.KtNodeTypes.RETURN\nimport org.jetbrains.kotlin.com.intellij.lang.ASTNode\nimport org.jetbrains.kotlin.psi.psiUtil.parents\n\n/**\n * Rule that checks using custom label\n */\nclass CustomLabel(configRules: List<RulesConfig>) : DiktatRule(\n    NAME_ID,\n    configRules,\n    listOf(CUSTOM_LABEL)\n) {\n    private val forEachReference = listOf(\"forEach\", \"forEachIndexed\")\n    private val labels = listOf(\"@loop\", \"@forEach\", \"@forEachIndexed\")\n    private val stopWords = listOf(RETURN, BREAK, CONTINUE)\n\n    override fun logic(node: ASTNode) {\n        if (node.elementType == LABEL_QUALIFIER && node.text !in labels && node.treeParent.elementType in stopWords) {\n            val nestedCount = node.parents().count {\n                it.elementType in loopType ||\n                        (it.elementType == CALL_EXPRESSION && it.findChildByType(REFERENCE_EXPRESSION)?.text in forEachReference)\n            }\n            if (nestedCount == 1) {\n                CUSTOM_LABEL.warn(configRules, emitWarn, node.text, node.startOffset, node)\n            }\n        }\n    }\n\n    companion object {\n        const val NAME_ID = \"custom-label\"\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/main/kotlin/com/saveourtool/diktat/ruleset/rules/chapter5/FunctionArgumentsSize.kt",
    "content": "package com.saveourtool.diktat.ruleset.rules.chapter5\n\nimport com.saveourtool.diktat.common.config.rules.RuleConfiguration\nimport com.saveourtool.diktat.common.config.rules.RulesConfig\nimport com.saveourtool.diktat.common.config.rules.getRuleConfig\nimport com.saveourtool.diktat.ruleset.constants.Warnings.TOO_MANY_PARAMETERS\nimport com.saveourtool.diktat.ruleset.rules.DiktatRule\n\nimport org.jetbrains.kotlin.KtNodeTypes\nimport org.jetbrains.kotlin.com.intellij.lang.ASTNode\nimport org.jetbrains.kotlin.lexer.KtTokens.IDENTIFIER\nimport org.jetbrains.kotlin.psi.KtFunction\n\n/**\n * Rule that checks that function doesn't contains too many parameters\n */\nclass FunctionArgumentsSize(configRules: List<RulesConfig>) : DiktatRule(\n    NAME_ID,\n    configRules,\n    listOf(TOO_MANY_PARAMETERS)\n) {\n    private val configuration: FunctionArgumentsSizeConfiguration by lazy {\n        FunctionArgumentsSizeConfiguration(configRules.getRuleConfig(TOO_MANY_PARAMETERS)?.configuration ?: emptyMap())\n    }\n\n    override fun logic(node: ASTNode) {\n        if (node.elementType == KtNodeTypes.FUN) {\n            checkFun(node, configuration.maxParameterSize)\n        }\n    }\n\n    @Suppress(\"UnsafeCallOnNullableType\")\n    private fun checkFun(node: ASTNode, maxParameterSize: Long) {\n        val parameterListSize = (node.psi as KtFunction).valueParameters.size\n        if (parameterListSize > maxParameterSize) {\n            TOO_MANY_PARAMETERS.warn(configRules, emitWarn,\n                \"${node.findChildByType(IDENTIFIER)!!.text} has $parameterListSize, but allowed $maxParameterSize\", node.startOffset, node)\n        }\n    }\n\n    /**\n     * [RuleConfiguration] for maximum number of parameters\n     */\n    class FunctionArgumentsSizeConfiguration(config: Map<String, String>) : RuleConfiguration(config) {\n        /**\n         * Maximum allowed number of function parameters\n         */\n        val maxParameterSize = config[\"maxParameterListSize\"]?.toLongOrNull() ?: MAX_DEFAULT_PARAMETER_SIZE\n    }\n\n    companion object {\n        const val MAX_DEFAULT_PARAMETER_SIZE = 5L\n        const val NAME_ID = \"argument-size\"\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/main/kotlin/com/saveourtool/diktat/ruleset/rules/chapter5/FunctionLength.kt",
    "content": "package com.saveourtool.diktat.ruleset.rules.chapter5\n\nimport com.saveourtool.diktat.common.config.rules.RuleConfiguration\nimport com.saveourtool.diktat.common.config.rules.RulesConfig\nimport com.saveourtool.diktat.common.config.rules.getRuleConfig\nimport com.saveourtool.diktat.ruleset.constants.Warnings.TOO_LONG_FUNCTION\nimport com.saveourtool.diktat.ruleset.rules.DiktatRule\nimport com.saveourtool.diktat.ruleset.utils.*\n\nimport org.jetbrains.kotlin.KtNodeTypes.FUN\nimport org.jetbrains.kotlin.com.intellij.lang.ASTNode\nimport org.jetbrains.kotlin.psi.KtFunction\n\n/**\n * Rule 5.1.1 check function length\n */\nclass FunctionLength(configRules: List<RulesConfig>) : DiktatRule(\n    NAME_ID,\n    configRules,\n    listOf(TOO_LONG_FUNCTION)\n) {\n    override fun logic(node: ASTNode) {\n        val configuration = FunctionLengthConfiguration(\n            configRules.getRuleConfig(TOO_LONG_FUNCTION)?.configuration ?: emptyMap()\n        )\n\n        if (node.elementType == FUN) {\n            checkFun(node, configuration)\n        }\n    }\n\n    private fun checkFun(node: ASTNode, configuration: FunctionLengthConfiguration) {\n        val copyNode = if (configuration.isIncludeHeader) {\n            node.clone() as ASTNode\n        } else {\n            ((node.psi as KtFunction)\n                .bodyExpression\n                ?.node\n                ?.clone() ?: return) as ASTNode\n        }\n        val sizeFun = countCodeLines(copyNode)\n        if (sizeFun > configuration.maxFunctionLength) {\n            TOO_LONG_FUNCTION.warn(configRules, emitWarn,\n                \"max length is ${configuration.maxFunctionLength}, but you have $sizeFun\",\n                node.startOffset, node)\n        }\n    }\n\n    /**\n     * [RuleConfiguration] for function length\n     */\n    class FunctionLengthConfiguration(config: Map<String, String>) : RuleConfiguration(config) {\n        /**\n         * Maximum allowed function length\n         */\n        val maxFunctionLength = config[\"maxFunctionLength\"]?.toLong() ?: MAX_FUNCTION_LENGTH\n\n        /**\n         * Whether function header (start of a declaration with parameter list and return type) is counted too\n         */\n        val isIncludeHeader = config[\"isIncludeHeader\"]?.toBoolean() ?: true\n    }\n\n    companion object {\n        private const val MAX_FUNCTION_LENGTH = 30L\n        const val NAME_ID = \"function-length\"\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/main/kotlin/com/saveourtool/diktat/ruleset/rules/chapter5/LambdaLengthRule.kt",
    "content": "package com.saveourtool.diktat.ruleset.rules.chapter5\n\nimport com.saveourtool.diktat.common.config.rules.RuleConfiguration\nimport com.saveourtool.diktat.common.config.rules.RulesConfig\nimport com.saveourtool.diktat.common.config.rules.getRuleConfig\nimport com.saveourtool.diktat.ruleset.constants.Warnings.TOO_MANY_LINES_IN_LAMBDA\nimport com.saveourtool.diktat.ruleset.rules.DiktatRule\nimport com.saveourtool.diktat.ruleset.utils.*\n\nimport org.jetbrains.kotlin.KtNodeTypes\nimport org.jetbrains.kotlin.com.intellij.lang.ASTNode\n\n/**\n * Rule 5.2.5 check lambda length without parameters\n */\nclass LambdaLengthRule(configRules: List<RulesConfig>) : DiktatRule(\n    NAME_ID,\n    configRules,\n    listOf(TOO_MANY_LINES_IN_LAMBDA)\n) {\n    private val configuration by lazy {\n        LambdaLengthConfiguration(\n            this.configRules.getRuleConfig(TOO_MANY_LINES_IN_LAMBDA)?.configuration ?: emptyMap()\n        )\n    }\n\n    override fun logic(node: ASTNode) {\n        if (node.elementType == KtNodeTypes.LAMBDA_EXPRESSION) {\n            checkLambda(node, configuration)\n        }\n    }\n\n    private fun checkLambda(node: ASTNode, configuration: LambdaLengthConfiguration) {\n        val sizeLambda = countCodeLines(node)\n        if (sizeLambda > configuration.maxLambdaLength && doesLambdaContainIt(node)) {\n            TOO_MANY_LINES_IN_LAMBDA.warn(configRules, emitWarn,\n                \"max length lambda without arguments is ${configuration.maxLambdaLength}, but you have $sizeLambda\",\n                node.startOffset, node)\n        }\n    }\n\n    /**\n     * [RuleConfiguration] for lambda length\n     */\n    class LambdaLengthConfiguration(config: Map<String, String>) : RuleConfiguration(config) {\n        /**\n         * Maximum allowed lambda length\n         */\n        val maxLambdaLength = config[\"maxLambdaLength\"]?.toLong() ?: MAX_LINES_IN_LAMBDA\n    }\n\n    companion object {\n        private const val MAX_LINES_IN_LAMBDA = 10L\n        const val NAME_ID = \"lambda-length\"\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/main/kotlin/com/saveourtool/diktat/ruleset/rules/chapter5/LambdaParameterOrder.kt",
    "content": "package com.saveourtool.diktat.ruleset.rules.chapter5\n\nimport com.saveourtool.diktat.common.config.rules.RulesConfig\nimport com.saveourtool.diktat.ruleset.constants.Warnings.LAMBDA_IS_NOT_LAST_PARAMETER\nimport com.saveourtool.diktat.ruleset.rules.DiktatRule\nimport com.saveourtool.diktat.ruleset.utils.hasChildOfType\n\nimport org.jetbrains.kotlin.KtNodeTypes\nimport org.jetbrains.kotlin.KtNodeTypes.FUNCTION_TYPE\nimport org.jetbrains.kotlin.KtNodeTypes.NULLABLE_TYPE\nimport org.jetbrains.kotlin.com.intellij.lang.ASTNode\nimport org.jetbrains.kotlin.lexer.KtTokens.IDENTIFIER\nimport org.jetbrains.kotlin.psi.KtFunction\nimport org.jetbrains.kotlin.utils.addToStdlib.ifNotEmpty\n\n/**\n * Rule that checks if parameter with function type is the last in parameter list\n */\nclass LambdaParameterOrder(configRules: List<RulesConfig>) : DiktatRule(\n    NAME_ID,\n    configRules,\n    listOf(LAMBDA_IS_NOT_LAST_PARAMETER)\n) {\n    override fun logic(node: ASTNode) {\n        if (node.elementType == KtNodeTypes.FUN) {\n            checkArguments(node)\n        }\n    }\n\n    @Suppress(\"UnsafeCallOnNullableType\")\n    private fun checkArguments(node: ASTNode) {\n        val funArguments = (node.psi as KtFunction).valueParameters\n        val sortArguments = funArguments\n            .sortedBy { valueParam ->\n                valueParam\n                    .typeReference\n                    ?.node\n                    ?.let { it.findChildByType(NULLABLE_TYPE) ?: it }\n                    ?.hasChildOfType(FUNCTION_TYPE)\n            }\n        funArguments.filterIndexed { index, ktParameter -> ktParameter != sortArguments[index] }.ifNotEmpty {\n            LAMBDA_IS_NOT_LAST_PARAMETER.warn(configRules, emitWarn, node.findChildByType(IDENTIFIER)!!.text,\n                first().node.startOffset, node)\n        }\n    }\n\n    companion object {\n        const val NAME_ID = \"lambda-parameter-order\"\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/main/kotlin/com/saveourtool/diktat/ruleset/rules/chapter5/NestedFunctionBlock.kt",
    "content": "package com.saveourtool.diktat.ruleset.rules.chapter5\n\nimport com.saveourtool.diktat.common.config.rules.RuleConfiguration\nimport com.saveourtool.diktat.common.config.rules.RulesConfig\nimport com.saveourtool.diktat.common.config.rules.getRuleConfig\nimport com.saveourtool.diktat.ruleset.constants.Warnings.NESTED_BLOCK\nimport com.saveourtool.diktat.ruleset.rules.DiktatRule\nimport com.saveourtool.diktat.ruleset.utils.findAllDescendantsWithSpecificType\nimport com.saveourtool.diktat.ruleset.utils.hasChildOfType\n\nimport org.jetbrains.kotlin.KtNodeTypes.CLASS\nimport org.jetbrains.kotlin.KtNodeTypes.FUN\nimport org.jetbrains.kotlin.KtNodeTypes.FUNCTION_LITERAL\nimport org.jetbrains.kotlin.KtNodeTypes.OBJECT_DECLARATION\nimport org.jetbrains.kotlin.com.intellij.lang.ASTNode\nimport org.jetbrains.kotlin.lexer.KtTokens.IDENTIFIER\nimport org.jetbrains.kotlin.lexer.KtTokens.LBRACE\nimport org.jetbrains.kotlin.psi.psiUtil.parents\n\n/**\n * Rule 5.1.2 Nested blokcs\n */\nclass NestedFunctionBlock(configRules: List<RulesConfig>) : DiktatRule(\n    NAME_ID,\n    configRules,\n    listOf(NESTED_BLOCK)\n) {\n    private val configuration: NestedBlockConfiguration by lazy {\n        NestedBlockConfiguration(configRules.getRuleConfig(NESTED_BLOCK)?.configuration ?: emptyMap())\n    }\n\n    override fun logic(node: ASTNode) {\n        if (node.elementType in nullificationType) {\n            countNestedBlocks(node, configuration.maxNestedBlockQuantity)\n        }\n    }\n\n    private fun countNestedBlocks(node: ASTNode, maxNestedBlockCount: Long) {\n        node.findAllDescendantsWithSpecificType(LBRACE)\n            .reversed()\n            .forEach { lbraceNode ->\n                val blockParent = lbraceNode\n                    .parents()\n                    .takeWhile { it != node }\n                    .takeIf { parentList -> parentList.map { it.elementType }.none { it in nullificationType } }\n                    ?.count { it.hasChildOfType(LBRACE) }\n                    ?: return\n                if (blockParent > maxNestedBlockCount) {\n                    NESTED_BLOCK.warn(configRules, emitWarn, node.findChildByType(IDENTIFIER)?.text ?: node.text,\n                        node.startOffset, node)\n                    return\n                }\n            }\n    }\n\n    /**\n     * [RuleConfiguration] for analyzing nested code blocks\n     */\n    class NestedBlockConfiguration(config: Map<String, String>) : RuleConfiguration(config) {\n        /**\n         * Maximum number of allowed levels of nested blocks\n         */\n        val maxNestedBlockQuantity = config[\"maxNestedBlockQuantity\"]?.toLong() ?: MAX_NESTED_BLOCK_COUNT\n    }\n\n    companion object {\n        private const val MAX_NESTED_BLOCK_COUNT = 4L\n        const val NAME_ID = \"nested-block\"\n\n        /**\n         * Nodes of these types reset counter of nested blocks\n         */\n        private val nullificationType = listOf(CLASS, FUN, OBJECT_DECLARATION, FUNCTION_LITERAL)\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/main/kotlin/com/saveourtool/diktat/ruleset/rules/chapter5/OverloadingArgumentsFunction.kt",
    "content": "package com.saveourtool.diktat.ruleset.rules.chapter5\n\nimport com.saveourtool.diktat.common.config.rules.RulesConfig\nimport com.saveourtool.diktat.ruleset.constants.Warnings.WRONG_OVERLOADING_FUNCTION_ARGUMENTS\nimport com.saveourtool.diktat.ruleset.rules.DiktatRule\nimport com.saveourtool.diktat.ruleset.utils.allSiblings\nimport com.saveourtool.diktat.ruleset.utils.findChildAfter\nimport com.saveourtool.diktat.ruleset.utils.findChildBefore\n\nimport org.jetbrains.kotlin.KtNodeTypes.FUN\nimport org.jetbrains.kotlin.KtNodeTypes.TYPE_REFERENCE\nimport org.jetbrains.kotlin.com.intellij.lang.ASTNode\nimport org.jetbrains.kotlin.lexer.KtTokens\nimport org.jetbrains.kotlin.lexer.KtTokens.IDENTIFIER\nimport org.jetbrains.kotlin.psi.KtFunction\nimport org.jetbrains.kotlin.psi.KtParameter\nimport org.jetbrains.kotlin.psi.psiUtil.startOffset\n\n/**\n * Rule that suggests to use functions with default parameters instead of multiple overloads\n */\nclass OverloadingArgumentsFunction(configRules: List<RulesConfig>) : DiktatRule(\n    NAME_ID,\n    configRules,\n    listOf(WRONG_OVERLOADING_FUNCTION_ARGUMENTS)\n) {\n    override fun logic(node: ASTNode) {\n        if (node.elementType == FUN) {\n            checkFun(node.psi as KtFunction)\n        }\n    }\n\n    @Suppress(\"UnsafeCallOnNullableType\")\n    private fun checkFun(funPsi: KtFunction) {\n        val allOverloadFunction = funPsi\n            .node\n            .allSiblings(withSelf = false)\n            .asSequence()\n            .filter { it.elementType == FUN }\n            .map { it.psi as KtFunction }\n            .filter { it.isOverloadedBy(funPsi) }\n            .filter { it.hasSameModifiers(funPsi) }\n            .filter { funPsi.node.findChildBefore(IDENTIFIER, TYPE_REFERENCE)?.text == it.node.findChildBefore(IDENTIFIER, TYPE_REFERENCE)?.text }\n            .filter { funPsi.node.findChildAfter(IDENTIFIER, TYPE_REFERENCE)?.text == it.node.findChildAfter(IDENTIFIER, TYPE_REFERENCE)?.text }\n            .toList()\n\n        if (allOverloadFunction.isNotEmpty()) {\n            WRONG_OVERLOADING_FUNCTION_ARGUMENTS.warn(configRules, emitWarn, funPsi.node.findChildByType(IDENTIFIER)!!.text, funPsi.startOffset, funPsi.node)\n        }\n    }\n\n    /**\n     * We can raise errors only on those methods that have same modifiers (inline/public/etc.)\n     */\n    private fun KtFunction.hasSameModifiers(other: KtFunction) =\n        this.getSortedModifiers() ==\n                other.getSortedModifiers()\n\n    private fun KtFunction.getSortedModifiers() = this.modifierList\n        ?.node\n        ?.getChildren(KtTokens.MODIFIER_KEYWORDS)\n        ?.map { it.text }\n        ?.sortedBy { it }\n\n    /**\n     * we need to compare following things for two functions:\n     * 1) that function arguments go in the same order in both method\n     * 2) that arguments have SAME names (you can think that it is not necessary,\n     * but usually if developer really wants to overload method - he will have same names of arguments)\n     * 3) arguments have same types (obviously)\n     *\n     * So we need to find methods with following arguments: foo(a: Int, b: Int) and foo(a: Int). foo(b: Int) is NOT suitable\n     */\n    private fun KtFunction.isOverloadedBy(other: KtFunction): Boolean {\n        // no need to process methods with different names\n        if (this.nameIdentifier?.text != other.nameIdentifier?.text) {\n            return false\n        }\n        // if this function has more arguments, than other, then we will compare it on the next iteration cycle (at logic() level)\n        // this hack will help us to point only to one function with smaller number of arguments\n        if (this.valueParameters.size < other.valueParameters.size) {\n            return false\n        }\n\n        for (i in 0 until other.valueParameters.size) {\n            // all arguments on the same position should match by name and type\n            if (this.valueParameters[i].getFunctionName() != other.valueParameters[i].getFunctionName() ||\n                    this.valueParameters[i].getFunctionType() != other.valueParameters[i].getFunctionType()\n            ) {\n                return false\n            }\n        }\n        return true\n    }\n\n    private fun KtParameter.getFunctionName() = this.nameIdentifier?.text\n    private fun KtParameter.getFunctionType() = this.typeReference?.text\n\n    companion object {\n        const val NAME_ID = \"overloading-default-values\"\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/main/kotlin/com/saveourtool/diktat/ruleset/rules/chapter5/ParameterNameInOuterLambdaRule.kt",
    "content": "package com.saveourtool.diktat.ruleset.rules.chapter5\n\nimport com.saveourtool.diktat.common.config.rules.RuleConfiguration\nimport com.saveourtool.diktat.common.config.rules.RulesConfig\nimport com.saveourtool.diktat.common.config.rules.getRuleConfig\nimport com.saveourtool.diktat.ruleset.constants.Warnings.PARAMETER_NAME_IN_OUTER_LAMBDA\nimport com.saveourtool.diktat.ruleset.rules.DiktatRule\nimport com.saveourtool.diktat.ruleset.utils.doesLambdaContainIt\nimport com.saveourtool.diktat.ruleset.utils.findAllDescendantsWithSpecificType\nimport com.saveourtool.diktat.ruleset.utils.hasExplicitIt\nimport com.saveourtool.diktat.ruleset.utils.hasItInLambda\nimport com.saveourtool.diktat.ruleset.utils.hasNoParameters\n\nimport org.jetbrains.kotlin.KtNodeTypes\nimport org.jetbrains.kotlin.com.intellij.lang.ASTNode\n\n/**\n * Rule 5.2.7 check parameter name in outer lambda\n */\nclass ParameterNameInOuterLambdaRule(configRules: List<RulesConfig>) : DiktatRule(\n    NAME_ID,\n    configRules,\n    listOf(PARAMETER_NAME_IN_OUTER_LAMBDA)\n) {\n    /**\n     * Configuration for the rule ParameterNameInOuterLambda\n     */\n    private val configuration by lazy {\n        ParameterNameInOuterLambdaConfiguration(\n            configRules.getRuleConfig(PARAMETER_NAME_IN_OUTER_LAMBDA)?.configuration\n                ?: emptyMap())\n    }\n\n    override fun logic(node: ASTNode) {\n        if (node.elementType == KtNodeTypes.LAMBDA_EXPRESSION) {\n            checkLambda(node)\n        }\n    }\n\n    private fun checkLambda(node: ASTNode) {\n        val strictMode = configuration.strictMode\n\n        val innerLambdaList = node.findAllDescendantsWithSpecificType(KtNodeTypes.LAMBDA_EXPRESSION, false)\n        val hasInnerLambda = innerLambdaList.isNotEmpty()\n\n        val outerLambdaHasNoParameterName = hasNoParameters(node) || node.hasExplicitIt()\n        val innerLambdasHasNoIt = !hasInnerLambda ||\n                innerLambdaList.all { innerLambda -> !hasItInLambda(innerLambda) }\n\n        if (!strictMode && outerLambdaHasNoParameterName && innerLambdasHasNoIt) {\n            return\n        }\n        if (hasInnerLambda && doesLambdaContainIt(node)) {\n            PARAMETER_NAME_IN_OUTER_LAMBDA.warn(\n                configRules, emitWarn,\n                \"lambda without arguments has inner lambda\",\n                node.startOffset, node,\n            )\n        }\n    }\n\n    /**\n     * ParameterNameInOuterLambdaConfiguration used when we need to allow the usage of 'it' in outer lambda\n     *\n     * @param config - map of strings with configuration options for a Parameter Name In Outer Lambda rule\n     */\n    class ParameterNameInOuterLambdaConfiguration(config: Map<String, String>) : RuleConfiguration(config) {\n        /**\n         * Flag (when false) allows to use `it` in outer lambda, if in inner lambdas would be no `it`\n         */\n        val strictMode = config[\"strictMode\"]?.toBoolean() ?: true\n    }\n\n    companion object {\n        const val NAME_ID = \"parameter-name-in-outer-lambda\"\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/main/kotlin/com/saveourtool/diktat/ruleset/rules/chapter6/AvoidEmptyPrimaryConstructor.kt",
    "content": "package com.saveourtool.diktat.ruleset.rules.chapter6\n\nimport com.saveourtool.diktat.common.config.rules.RulesConfig\nimport com.saveourtool.diktat.ruleset.constants.Warnings.EMPTY_PRIMARY_CONSTRUCTOR\nimport com.saveourtool.diktat.ruleset.rules.DiktatRule\n\nimport org.jetbrains.kotlin.KtNodeTypes.CLASS\nimport org.jetbrains.kotlin.com.intellij.lang.ASTNode\nimport org.jetbrains.kotlin.psi.KtClass\n\n/**\n * This rule checks if a class has an empty primary constructor.\n */\nclass AvoidEmptyPrimaryConstructor(configRules: List<RulesConfig>) : DiktatRule(\n    NAME_ID,\n    configRules,\n    listOf(EMPTY_PRIMARY_CONSTRUCTOR)\n) {\n    override fun logic(node: ASTNode) {\n        if (node.elementType == CLASS) {\n            checkClass(node.psi as KtClass)\n        }\n    }\n\n    @Suppress(\"UnsafeCallOnNullableType\")\n    private fun checkClass(ktClass: KtClass) {\n        if (ktClass.primaryConstructor?.valueParameters?.isNotEmpty() != false || ktClass.primaryConstructorModifierList != null) {\n            return\n        }\n        EMPTY_PRIMARY_CONSTRUCTOR.warnAndFix(configRules, emitWarn, isFixMode, ktClass.nameIdentifier!!.text,\n            ktClass.node.startOffset, ktClass.node) {\n            ktClass.node.removeChild(ktClass.primaryConstructor!!.node)\n        }\n    }\n\n    companion object {\n        const val NAME_ID = \"avoid-empty-primary-constructor\"\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/main/kotlin/com/saveourtool/diktat/ruleset/rules/chapter6/AvoidUtilityClass.kt",
    "content": "package com.saveourtool.diktat.ruleset.rules.chapter6\n\nimport com.saveourtool.diktat.common.config.rules.RulesConfig\nimport com.saveourtool.diktat.common.config.rules.getCommonConfiguration\nimport com.saveourtool.diktat.ruleset.constants.Warnings.AVOID_USING_UTILITY_CLASS\nimport com.saveourtool.diktat.ruleset.rules.DiktatRule\nimport com.saveourtool.diktat.ruleset.utils.*\n\nimport org.jetbrains.kotlin.KtNodeTypes.CLASS\nimport org.jetbrains.kotlin.KtNodeTypes.CLASS_BODY\nimport org.jetbrains.kotlin.KtNodeTypes.FUN\nimport org.jetbrains.kotlin.KtNodeTypes.OBJECT_DECLARATION\nimport org.jetbrains.kotlin.KtNodeTypes.PRIMARY_CONSTRUCTOR\nimport org.jetbrains.kotlin.com.intellij.lang.ASTNode\nimport org.jetbrains.kotlin.kdoc.lexer.KDocTokens.KDOC\nimport org.jetbrains.kotlin.lexer.KtTokens.BLOCK_COMMENT\nimport org.jetbrains.kotlin.lexer.KtTokens.EOL_COMMENT\nimport org.jetbrains.kotlin.lexer.KtTokens.IDENTIFIER\nimport org.jetbrains.kotlin.lexer.KtTokens.LBRACE\nimport org.jetbrains.kotlin.lexer.KtTokens.RBRACE\nimport org.jetbrains.kotlin.lexer.KtTokens.WHITE_SPACE\nimport org.jetbrains.kotlin.psi.psiUtil.children\n\nimport java.util.Locale\n\n/**\n * Rule 6.4.1 checks that class/object, with a word \"util\" in its name, has only functions.\n */\nclass AvoidUtilityClass(configRules: List<RulesConfig>) : DiktatRule(\n    NAME_ID,\n    configRules,\n    listOf(AVOID_USING_UTILITY_CLASS)\n) {\n    override fun logic(node: ASTNode) {\n        val config = configRules.getCommonConfiguration()\n        val filePath = node.getFilePath()\n        if (!node.hasTestAnnotation() && !isLocatedInTest(filePath.splitPathToDirs(), config.testAnchors)) {\n            @Suppress(\"COLLAPSE_IF_STATEMENTS\")\n            if (node.elementType == OBJECT_DECLARATION || node.elementType == CLASS) {\n                checkClass(node)\n            }\n        }\n    }\n\n    @Suppress(\"UnsafeCallOnNullableType\", \"WRONG_NEWLINES\")\n    private fun checkClass(node: ASTNode) {\n        // checks that class/object doesn't contain primary constructor and its identifier doesn't has \"utli\"\n        if (!node.hasChildOfType(IDENTIFIER) || node.hasChildOfType(PRIMARY_CONSTRUCTOR) ||\n                !node.findChildByType(IDENTIFIER)!!.text.lowercase(Locale.getDefault()).contains(\"util\")) {\n            return\n        }\n        node.findChildByType(CLASS_BODY)\n            ?.children()\n            ?.toList()\n            ?.takeIf { childList -> childList.all { it.elementType in utilityClassChildren } }\n            ?.filter { it.elementType == FUN }\n            ?.ifEmpty { return }\n            ?: return\n        AVOID_USING_UTILITY_CLASS.warn(configRules, emitWarn, node.findChildByType(IDENTIFIER)?.text ?: node.text, node.startOffset, node)\n    }\n\n    companion object {\n        const val NAME_ID = \"avoid-utility-class\"\n        private val utilityClassChildren = listOf(LBRACE, WHITE_SPACE, FUN, RBRACE, KDOC,\n            EOL_COMMENT, BLOCK_COMMENT, OBJECT_DECLARATION)\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/main/kotlin/com/saveourtool/diktat/ruleset/rules/chapter6/CustomGetterSetterRule.kt",
    "content": "package com.saveourtool.diktat.ruleset.rules.chapter6\n\nimport com.saveourtool.diktat.common.config.rules.RulesConfig\nimport com.saveourtool.diktat.ruleset.constants.Warnings.CUSTOM_GETTERS_SETTERS\nimport com.saveourtool.diktat.ruleset.rules.DiktatRule\nimport com.saveourtool.diktat.ruleset.utils.*\n\nimport org.jetbrains.kotlin.KtNodeTypes.MODIFIER_LIST\nimport org.jetbrains.kotlin.KtNodeTypes.PROPERTY_ACCESSOR\nimport org.jetbrains.kotlin.com.intellij.lang.ASTNode\nimport org.jetbrains.kotlin.lexer.KtTokens.GET_KEYWORD\nimport org.jetbrains.kotlin.lexer.KtTokens.OVERRIDE_KEYWORD\nimport org.jetbrains.kotlin.lexer.KtTokens.PRIVATE_KEYWORD\nimport org.jetbrains.kotlin.lexer.KtTokens.SET_KEYWORD\nimport org.jetbrains.kotlin.psi.KtProperty\n\n/**\n * Inspection that checks that no custom getters and setters are used for properties.\n */\nclass CustomGetterSetterRule(configRules: List<RulesConfig>) : DiktatRule(\n    NAME_ID,\n    configRules,\n    listOf(CUSTOM_GETTERS_SETTERS)\n) {\n    override fun logic(node: ASTNode) {\n        if (node.elementType == PROPERTY_ACCESSOR) {\n            checkForCustomGetersSetters(node)\n        }\n    }\n\n    private fun checkForCustomGetersSetters(node: ASTNode) {\n        val getter = node.getFirstChildWithType(GET_KEYWORD)\n        val setter = node.getFirstChildWithType(SET_KEYWORD)\n        val isPrivateSetter = node.getFirstChildWithType(MODIFIER_LIST)?.hasAnyChildOfTypes(PRIVATE_KEYWORD) ?: false\n        val isOverrideGetter = node.treeParent.getFirstChildWithType(MODIFIER_LIST)?.hasAnyChildOfTypes(OVERRIDE_KEYWORD) ?: false\n\n        // find matching node\n        if (isPairPropertyBackingField(node.treeParent?.psi as? KtProperty, null)) {\n            return\n        }\n\n        setter?.let {\n            // only private custom setters are allowed\n            if (!isPrivateSetter) {\n                CUSTOM_GETTERS_SETTERS.warn(configRules, emitWarn, setter.text, setter.startOffset, node)\n            }\n        }\n\n        getter?.let {\n            // only override getter are allowed\n            if (!isOverrideGetter) {\n                CUSTOM_GETTERS_SETTERS.warn(configRules, emitWarn, getter.text, getter.startOffset, node)\n            }\n        }\n    }\n\n    companion object {\n        const val NAME_ID = \"custom-getter-setter\"\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/main/kotlin/com/saveourtool/diktat/ruleset/rules/chapter6/ExtensionFunctionsInFileRule.kt",
    "content": "package com.saveourtool.diktat.ruleset.rules.chapter6\n\nimport com.saveourtool.diktat.common.config.rules.RulesConfig\nimport com.saveourtool.diktat.ruleset.constants.Warnings.EXTENSION_FUNCTION_WITH_CLASS\nimport com.saveourtool.diktat.ruleset.rules.DiktatRule\nimport com.saveourtool.diktat.ruleset.utils.findAllDescendantsWithSpecificType\nimport com.saveourtool.diktat.ruleset.utils.getAllChildrenWithType\nimport com.saveourtool.diktat.ruleset.utils.getFirstChildWithType\nimport com.saveourtool.diktat.ruleset.utils.prevSibling\n\nimport org.jetbrains.kotlin.KtNodeTypes.CLASS\nimport org.jetbrains.kotlin.KtNodeTypes.FUN\nimport org.jetbrains.kotlin.KtNodeTypes.TYPE_REFERENCE\nimport org.jetbrains.kotlin.com.intellij.lang.ASTNode\nimport org.jetbrains.kotlin.com.intellij.psi.PsiElement\nimport org.jetbrains.kotlin.com.intellij.psi.impl.source.tree.LeafPsiElement\nimport org.jetbrains.kotlin.lexer.KtModifierKeywordToken\nimport org.jetbrains.kotlin.lexer.KtTokens.EXTERNAL_KEYWORD\nimport org.jetbrains.kotlin.lexer.KtTokens.IDENTIFIER\nimport org.jetbrains.kotlin.psi.KtClass\nimport org.jetbrains.kotlin.psi.KtFunction\nimport org.jetbrains.kotlin.psi.psiUtil.allChildren\nimport org.jetbrains.kotlin.psi.stubs.elements.KtFileElementType\n\n/**\n * This rule checks if there are any extension functions for the class in the same file, where it is defined\n */\nclass ExtensionFunctionsInFileRule(configRules: List<RulesConfig>) : DiktatRule(\n    NAME_ID,\n    configRules,\n    listOf(EXTENSION_FUNCTION_WITH_CLASS)\n) {\n    override fun logic(node: ASTNode) {\n        if (node.elementType == KtFileElementType.INSTANCE) {\n            val classNames = collectAllClassNames(node)\n\n            collectAllExtensionFunctionsWithSameClassName(node, classNames).forEach {\n                fireWarning(it)\n            }\n        }\n    }\n\n    /**\n     * Collects all class names in the [file], except those with modifiers from\n     * the [ignore list][ignoredModifierTypes].\n     *\n     * @throws IllegalArgumentException if [file] is not a\n     *   [FILE][KtFileElementType.INSTANCE] node.\n     */\n    private fun collectAllClassNames(file: ASTNode): List<String> {\n        require(file.elementType == KtFileElementType.INSTANCE)\n\n        val classes = file.findAllDescendantsWithSpecificType(CLASS)\n\n        return classes.asSequence()\n            .map(ASTNode::getPsi)\n            .filterIsInstance(KtClass::class.java)\n            .filter { clazz ->\n                clazz.modifierTypes().none { modifierType ->\n                    modifierType in ignoredModifierTypes\n                }\n            }\n            .map(KtClass::getName)\n            .filterNotNull()\n            .toList()\n    }\n\n    private fun fireWarning(node: ASTNode) {\n        EXTENSION_FUNCTION_WITH_CLASS.warn(configRules, emitWarn, \"fun ${(node.psi as KtFunction).name}\", node.startOffset, node)\n    }\n\n    private fun collectAllExtensionFunctionsWithSameClassName(node: ASTNode, classNames: List<String>): List<ASTNode> =\n        node.getAllChildrenWithType(FUN).filter { isExtensionFunctionWithClassName(it, classNames) }\n\n    @Suppress(\"UnsafeCallOnNullableType\")\n    private fun isExtensionFunctionWithClassName(node: ASTNode, classNames: List<String>): Boolean =\n        node.getFirstChildWithType(IDENTIFIER)!!.prevSibling { it.elementType == TYPE_REFERENCE }?.text in classNames\n\n    companion object {\n        const val NAME_ID = \"extension-functions-class-file\"\n\n        /**\n         * Types of class/interface modifiers which, if present, don't trigger\n         * the warning.\n         *\n         * @since 1.2.5\n         */\n        private val ignoredModifierTypes: Array<out KtModifierKeywordToken> = arrayOf(\n            EXTERNAL_KEYWORD,\n        )\n\n        /**\n         * @since 1.2.5\n         */\n        private fun KtClass.modifiers(): Sequence<PsiElement> =\n            modifierList?.allChildren ?: emptySequence()\n\n        /**\n         * @since 1.2.5\n         */\n        private fun KtClass.modifierTypes(): Sequence<KtModifierKeywordToken> =\n            modifiers()\n                .filterIsInstance<LeafPsiElement>()\n                .map(LeafPsiElement::getElementType)\n                .filterIsInstance<KtModifierKeywordToken>()\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/main/kotlin/com/saveourtool/diktat/ruleset/rules/chapter6/ExtensionFunctionsSameNameRule.kt",
    "content": "package com.saveourtool.diktat.ruleset.rules.chapter6\n\nimport com.saveourtool.diktat.common.config.rules.RulesConfig\nimport com.saveourtool.diktat.ruleset.constants.Warnings.EXTENSION_FUNCTION_SAME_SIGNATURE\nimport com.saveourtool.diktat.ruleset.rules.DiktatRule\nimport com.saveourtool.diktat.ruleset.utils.findAllDescendantsWithSpecificType\nimport com.saveourtool.diktat.ruleset.utils.findChildAfter\nimport com.saveourtool.diktat.ruleset.utils.findChildBefore\nimport com.saveourtool.diktat.ruleset.utils.findLeafWithSpecificType\nimport com.saveourtool.diktat.ruleset.utils.getAllChildrenWithType\nimport com.saveourtool.diktat.ruleset.utils.getFirstChildWithType\nimport com.saveourtool.diktat.ruleset.utils.hasChildOfType\n\nimport org.jetbrains.kotlin.KtNodeTypes.CLASS\nimport org.jetbrains.kotlin.KtNodeTypes.FUN\nimport org.jetbrains.kotlin.KtNodeTypes.SUPER_TYPE_CALL_ENTRY\nimport org.jetbrains.kotlin.KtNodeTypes.SUPER_TYPE_LIST\nimport org.jetbrains.kotlin.KtNodeTypes.TYPE_REFERENCE\nimport org.jetbrains.kotlin.KtNodeTypes.VALUE_PARAMETER_LIST\nimport org.jetbrains.kotlin.com.intellij.lang.ASTNode\nimport org.jetbrains.kotlin.lexer.KtTokens.COLON\nimport org.jetbrains.kotlin.lexer.KtTokens.DOT\nimport org.jetbrains.kotlin.lexer.KtTokens.IDENTIFIER\nimport org.jetbrains.kotlin.psi.KtClass\nimport org.jetbrains.kotlin.psi.KtNamedFunction\nimport org.jetbrains.kotlin.psi.KtParameterList\nimport org.jetbrains.kotlin.psi.stubs.elements.KtFileElementType\n\ninternal typealias RelatedClasses = List<Pair<String, String>>\ninternal typealias SimilarSignatures = List<Pair<ExtensionFunctionsSameNameRule.ExtensionFunction, ExtensionFunctionsSameNameRule.ExtensionFunction>>\n\n/**\n * This rule checks if extension functions with the same signature don't have related classes\n */\nclass ExtensionFunctionsSameNameRule(configRules: List<RulesConfig>) : DiktatRule(\n    NAME_ID,\n    configRules,\n    listOf(EXTENSION_FUNCTION_SAME_SIGNATURE)\n) {\n    override fun logic(node: ASTNode) {\n        /*\n         * 1) Collect all classes that extend other classes (collect related classes)\n         * 2) Collect all extension functions with same signature\n         * 3) Check if classes of functions are related\n         */\n        if (node.elementType == KtFileElementType.INSTANCE) {\n            val relatedClasses = collectAllRelatedClasses(node)\n            val extFunctionsWithSameName = collectAllExtensionFunctions(node)\n            handleFunctions(relatedClasses, extFunctionsWithSameName)\n        }\n    }\n\n    // Fixme: should find all related classes in project, not only in file\n    @Suppress(\"UnsafeCallOnNullableType\", \"TYPE_ALIAS\")\n    private fun collectAllRelatedClasses(node: ASTNode): List<Pair<String, String>> {\n        val classListWithInheritance = node\n            .findAllDescendantsWithSpecificType(CLASS)\n            .filterNot { (it.psi as KtClass).isInterface() }\n            .filter { it.hasChildOfType(SUPER_TYPE_LIST) }\n\n        val pairs: MutableList<Pair<String, String>> = mutableListOf()\n        classListWithInheritance.forEach { classNode ->\n            val callEntries = classNode.findChildByType(SUPER_TYPE_LIST)!!.getAllChildrenWithType(SUPER_TYPE_CALL_ENTRY)\n\n            callEntries.forEach { entry ->\n                val className = (classNode.psi as KtClass).name!!\n                val entryName = entry.findLeafWithSpecificType(IDENTIFIER)!!\n                pairs.add(Pair(className, entryName.text))\n            }\n        }\n        return pairs\n    }\n\n    @Suppress(\"UnsafeCallOnNullableType\", \"TYPE_ALIAS\")\n    private fun collectAllExtensionFunctions(node: ASTNode): SimilarSignatures {\n        val extensionFunctionList = node.findAllDescendantsWithSpecificType(FUN).filter { it.hasChildOfType(TYPE_REFERENCE) && it.hasChildOfType(DOT) }\n        val distinctFunctionSignatures: MutableMap<FunctionSignature, ASTNode> = mutableMapOf()  // maps function signatures on node it is used by\n        val extensionFunctionsPairs: MutableList<Pair<ExtensionFunction, ExtensionFunction>> = mutableListOf()  // pairs extension functions with same signature\n\n        extensionFunctionList.forEach { func ->\n            val functionName = (func.psi as KtNamedFunction).name!!\n            // List<String> is used to show param names in warning\n            val params = (func.getFirstChildWithType(VALUE_PARAMETER_LIST)!!.psi as KtParameterList).parameters.map { it.name!! }\n            val returnType = func.findChildAfter(COLON, TYPE_REFERENCE)?.text\n            val className = func.findChildBefore(DOT, TYPE_REFERENCE)!!.text\n            val signature = FunctionSignature(functionName, params, returnType)\n\n            if (distinctFunctionSignatures.contains(signature)) {\n                val secondFuncClassName = distinctFunctionSignatures[signature]!!.findChildBefore(DOT, TYPE_REFERENCE)!!.text\n                extensionFunctionsPairs.add(Pair(\n                    ExtensionFunction(secondFuncClassName, signature, distinctFunctionSignatures[signature]!!),\n                    ExtensionFunction(className, signature, func)))\n            } else {\n                distinctFunctionSignatures[signature] = func\n            }\n        }\n\n        return extensionFunctionsPairs\n    }\n\n    private fun handleFunctions(relatedClasses: RelatedClasses, functions: SimilarSignatures) {\n        functions.forEach {\n            val firstClassName = it.first.className\n            val secondClassName = it.second.className\n\n            if (relatedClasses.hasRelatedClasses(Pair(firstClassName, secondClassName))) {\n                raiseWarning(it.first.node, it.first, it.second)\n                raiseWarning(it.second.node, it.first, it.second)\n            }\n        }\n    }\n\n    private fun RelatedClasses.hasRelatedClasses(pair: Pair<String, String>) = any {\n        it.first == pair.first && it.second == pair.second || it.first == pair.second && it.second == pair.first\n    }\n\n    private fun raiseWarning(\n        node: ASTNode,\n        firstFunc: ExtensionFunction,\n        secondFunc: ExtensionFunction\n    ) {\n        EXTENSION_FUNCTION_SAME_SIGNATURE.warn(configRules, emitWarn, \"$firstFunc and $secondFunc\", node.startOffset, node)\n    }\n\n    /**\n     * Class that represents a function's signature\n     * @property name function name\n     * @property parameters function parameters as strings\n     * @property returnType return type of a function if it is explicitly set\n     */\n    internal data class FunctionSignature(\n        val name: String,\n        val parameters: List<String>,\n        val returnType: String?\n    ) {\n        override fun toString() = \"$name$parameters${returnType?.let { \": $it\" } ?: \"\"}\"\n    }\n\n    /**\n     * Class that represents an extension function\n     * @property className name of receiver class\n     * @property signature a [FunctionSignature] of a function\n     * @property node a [ASTNode] that represents this function\n     */\n    internal data class ExtensionFunction(\n        val className: String,\n        val signature: FunctionSignature,\n        val node: ASTNode\n    ) {\n        override fun toString() = \"fun $className.$signature\"\n    }\n\n    companion object {\n        const val NAME_ID = \"extension-functions-same-name\"\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/main/kotlin/com/saveourtool/diktat/ruleset/rules/chapter6/ImplicitBackingPropertyRule.kt",
    "content": "package com.saveourtool.diktat.ruleset.rules.chapter6\n\nimport com.saveourtool.diktat.common.config.rules.RulesConfig\nimport com.saveourtool.diktat.ruleset.constants.Warnings.NO_CORRESPONDING_PROPERTY\nimport com.saveourtool.diktat.ruleset.rules.DiktatRule\nimport com.saveourtool.diktat.ruleset.utils.findAllDescendantsWithSpecificType\nimport com.saveourtool.diktat.ruleset.utils.getFirstChildWithType\nimport com.saveourtool.diktat.ruleset.utils.hasAnyChildOfTypes\nimport com.saveourtool.diktat.ruleset.utils.hasChildOfType\n\nimport org.jetbrains.kotlin.KtNodeTypes.BLOCK\nimport org.jetbrains.kotlin.KtNodeTypes.CLASS_BODY\nimport org.jetbrains.kotlin.KtNodeTypes.DOT_QUALIFIED_EXPRESSION\nimport org.jetbrains.kotlin.KtNodeTypes.PROPERTY\nimport org.jetbrains.kotlin.KtNodeTypes.PROPERTY_ACCESSOR\nimport org.jetbrains.kotlin.KtNodeTypes.REFERENCE_EXPRESSION\nimport org.jetbrains.kotlin.KtNodeTypes.RETURN\nimport org.jetbrains.kotlin.com.intellij.lang.ASTNode\nimport org.jetbrains.kotlin.lexer.KtTokens.GET_KEYWORD\nimport org.jetbrains.kotlin.lexer.KtTokens.IDENTIFIER\nimport org.jetbrains.kotlin.lexer.KtTokens.SET_KEYWORD\nimport org.jetbrains.kotlin.psi.KtProperty\n\n/**\n * This rule checks if there is a backing property for field with property accessors, in case they don't use field keyword\n */\nclass ImplicitBackingPropertyRule(configRules: List<RulesConfig>) : DiktatRule(\n    NAME_ID,\n    configRules,\n    listOf(NO_CORRESPONDING_PROPERTY)\n) {\n    override fun logic(node: ASTNode) {\n        if (node.elementType == CLASS_BODY) {\n            findAllProperties(node)\n        }\n    }\n\n    @Suppress(\"UnsafeCallOnNullableType\")\n    private fun findAllProperties(node: ASTNode) {\n        val properties = node.getChildren(null).filter { it.elementType == PROPERTY }\n\n        val propsWithBackSymbol = properties\n            .filter { it.getFirstChildWithType(IDENTIFIER)!!.text.startsWith(\"_\") }\n            .map {\n                it.getFirstChildWithType(IDENTIFIER)!!.text\n            }\n\n        properties.filter { it.hasAnyChildOfTypes(PROPERTY_ACCESSOR) }.forEach {\n            validateAccessors(it, propsWithBackSymbol)\n        }\n    }\n\n    private fun validateAccessors(node: ASTNode, propsWithBackSymbol: List<String>) {\n        val accessors = node.findAllDescendantsWithSpecificType(PROPERTY_ACCESSOR).filter { it.hasChildOfType(BLOCK) }  // exclude get with expression body\n\n        accessors.filter { it.hasChildOfType(GET_KEYWORD) }.forEach { handleGetAccessors(it, node, propsWithBackSymbol) }\n        accessors.filter { it.hasChildOfType(SET_KEYWORD) }.forEach { handleSetAccessors(it, node, propsWithBackSymbol) }\n    }\n\n    @Suppress(\"UnsafeCallOnNullableType\")\n    private fun handleGetAccessors(\n        accessor: ASTNode,\n        node: ASTNode,\n        propsWithBackSymbol: List<String>\n    ) {\n        val refExprs = accessor\n            .findAllDescendantsWithSpecificType(RETURN)\n            .filterNot { it.hasChildOfType(DOT_QUALIFIED_EXPRESSION) }\n            .flatMap { it.findAllDescendantsWithSpecificType(REFERENCE_EXPRESSION) }\n\n        val localProps = accessor\n            .findAllDescendantsWithSpecificType(PROPERTY)\n            .map { (it.psi as KtProperty).name!! }\n        // If refExprs is empty then we assume that it returns some constant\n        if (refExprs.isNotEmpty()) {\n            handleReferenceExpressions(node, refExprs, propsWithBackSymbol, localProps)\n        }\n    }\n\n    @Suppress(\"UnsafeCallOnNullableType\")\n    private fun handleSetAccessors(\n        accessor: ASTNode,\n        node: ASTNode,\n        propsWithBackSymbol: List<String>\n    ) {\n        val refExprs = accessor.findAllDescendantsWithSpecificType(REFERENCE_EXPRESSION)\n\n        // In set we don't check for local properties. At least one reference expression should contain field or _prop\n        if (refExprs.isNotEmpty()) {\n            handleReferenceExpressions(node, refExprs, propsWithBackSymbol, null)\n        }\n    }\n\n    @Suppress(\"UnsafeCallOnNullableType\")\n    private fun handleReferenceExpressions(node: ASTNode,\n                                           expressions: List<ASTNode>,\n                                           backingPropertiesNames: List<String>,\n                                           localProperties: List<String>?\n    ) {\n        if (expressions.none {\n            backingPropertiesNames.contains(it.text) || it.text == \"field\" || localProperties?.contains(it.text) == true\n        }) {\n            raiseWarning(node, node.getFirstChildWithType(IDENTIFIER)!!.text)\n        }\n    }\n\n    private fun raiseWarning(node: ASTNode, propName: String) {\n        NO_CORRESPONDING_PROPERTY.warn(configRules, emitWarn,\n            \"$propName has no corresponding property with name _$propName\", node.startOffset, node)\n    }\n\n    companion object {\n        const val NAME_ID = \"implicit-backing-property\"\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/main/kotlin/com/saveourtool/diktat/ruleset/rules/chapter6/PropertyAccessorFields.kt",
    "content": "package com.saveourtool.diktat.ruleset.rules.chapter6\n\nimport com.saveourtool.diktat.common.config.rules.RulesConfig\nimport com.saveourtool.diktat.ruleset.constants.Warnings.WRONG_NAME_OF_VARIABLE_INSIDE_ACCESSOR\nimport com.saveourtool.diktat.ruleset.rules.DiktatRule\nimport com.saveourtool.diktat.ruleset.utils.findAllDescendantsWithSpecificType\nimport com.saveourtool.diktat.ruleset.utils.isGoingAfter\n\nimport org.jetbrains.kotlin.KtNodeTypes.BLOCK\nimport org.jetbrains.kotlin.KtNodeTypes.CALL_EXPRESSION\nimport org.jetbrains.kotlin.KtNodeTypes.DOT_QUALIFIED_EXPRESSION\nimport org.jetbrains.kotlin.KtNodeTypes.PROPERTY\nimport org.jetbrains.kotlin.KtNodeTypes.PROPERTY_ACCESSOR\nimport org.jetbrains.kotlin.KtNodeTypes.REFERENCE_EXPRESSION\nimport org.jetbrains.kotlin.KtNodeTypes.THIS_EXPRESSION\nimport org.jetbrains.kotlin.KtNodeTypes.TYPE_REFERENCE\nimport org.jetbrains.kotlin.com.intellij.lang.ASTNode\nimport org.jetbrains.kotlin.com.intellij.psi.tree.TokenSet\nimport org.jetbrains.kotlin.lexer.KtTokens.IDENTIFIER\nimport org.jetbrains.kotlin.psi.KtProperty\n\n/**\n * Rule check that never use the name of a variable in the custom getter or setter\n */\nclass PropertyAccessorFields(configRules: List<RulesConfig>) : DiktatRule(\n    NAME_ID,\n    configRules,\n    listOf(WRONG_NAME_OF_VARIABLE_INSIDE_ACCESSOR)\n) {\n    override fun logic(node: ASTNode) {\n        if (node.elementType == PROPERTY_ACCESSOR) {\n            checkPropertyAccessor(node)\n        }\n    }\n\n    // fixme should use shadow-check when it will be done\n    private fun checkPropertyAccessor(node: ASTNode) {\n        val leftValue = node.treeParent.findChildByType(IDENTIFIER) ?: return\n        val isNotExtensionProperty = leftValue.treePrev?.treePrev?.elementType != TYPE_REFERENCE\n        val firstReferenceWithSameName = node\n            .findAllDescendantsWithSpecificType(REFERENCE_EXPRESSION)\n            .mapNotNull { it.findChildByType(IDENTIFIER) }\n            .firstOrNull {\n                it.text == leftValue.text &&\n                        (it.treeParent.treeParent.elementType != DOT_QUALIFIED_EXPRESSION ||\n                                it.treeParent.treeParent.firstChildNode.elementType == THIS_EXPRESSION)\n            }\n        val isContainLocalVarSameName = node\n            .findChildByType(BLOCK)\n            ?.getChildren(TokenSet.create(PROPERTY))\n            ?.filter { (it.psi as KtProperty).nameIdentifier?.text == leftValue.text }\n            ?.none { firstReferenceWithSameName?.isGoingAfter(it) ?: false } ?: true\n        val isNotCallExpression = firstReferenceWithSameName?.treeParent?.treeParent?.elementType != CALL_EXPRESSION\n        if (firstReferenceWithSameName != null && isContainLocalVarSameName && isNotCallExpression && isNotExtensionProperty) {\n            WRONG_NAME_OF_VARIABLE_INSIDE_ACCESSOR.warn(configRules, emitWarn, node.text, node.startOffset, node)\n        }\n    }\n\n    companion object {\n        const val NAME_ID = \"getter-setter-fields\"\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/main/kotlin/com/saveourtool/diktat/ruleset/rules/chapter6/RunInScript.kt",
    "content": "package com.saveourtool.diktat.ruleset.rules.chapter6\n\nimport com.saveourtool.diktat.common.config.rules.RulesConfig\nimport com.saveourtool.diktat.ruleset.constants.Warnings.RUN_IN_SCRIPT\nimport com.saveourtool.diktat.ruleset.rules.DiktatRule\nimport com.saveourtool.diktat.ruleset.utils.*\nimport com.saveourtool.diktat.util.isKotlinScript\n\nimport org.jetbrains.kotlin.KtNodeTypes.CALL_EXPRESSION\nimport org.jetbrains.kotlin.KtNodeTypes.DOT_QUALIFIED_EXPRESSION\nimport org.jetbrains.kotlin.KtNodeTypes.LAMBDA_ARGUMENT\nimport org.jetbrains.kotlin.KtNodeTypes.LAMBDA_EXPRESSION\nimport org.jetbrains.kotlin.KtNodeTypes.PARENTHESIZED\nimport org.jetbrains.kotlin.KtNodeTypes.SCRIPT_INITIALIZER\nimport org.jetbrains.kotlin.KtNodeTypes.VALUE_ARGUMENT\nimport org.jetbrains.kotlin.KtNodeTypes.VALUE_ARGUMENT_LIST\nimport org.jetbrains.kotlin.com.intellij.lang.ASTNode\nimport org.jetbrains.kotlin.com.intellij.psi.impl.source.tree.CompositeElement\n\n/**\n * Rule that checks if kts script contains other functions except run code\n * In .kts files allow use only property declaration, function, classes, and code inside `run` block\n * In gradle.kts files allow to call binary expression with EQ, expression and dot qualified expression in addition to everything used in .kts files\n */\nclass RunInScript(\n    configRules: List<RulesConfig>,\n) : DiktatRule(\n    id = NAME_ID,\n    configRules = configRules,\n    inspections = listOf(RUN_IN_SCRIPT),\n) {\n    override fun logic(node: ASTNode) {\n        if (node.elementType == SCRIPT_INITIALIZER && node.getFilePath().isKotlinScript()) {\n            if (node.getFilePath().isGradleScript()) {\n                checkGradleNode(node)\n            } else {\n                checkScript(node)\n            }\n        }\n    }\n\n    private fun checkGradleNode(node: ASTNode) {\n        val astNode = if (node.hasEqBinaryExpression()) {\n            return\n        } else {\n            when (node.firstChildNode.elementType) {\n                PARENTHESIZED -> node.firstChildNode\n                else -> node\n            }\n        }\n        if (!astNode.hasChildOfType(CALL_EXPRESSION) && !astNode.hasChildOfType(DOT_QUALIFIED_EXPRESSION)) {\n            warnRunInScript(astNode)\n        }\n    }\n\n    private fun checkScript(node: ASTNode) {\n        val isLambdaArgument = node.firstChildNode.hasChildOfType(LAMBDA_ARGUMENT)\n        val isLambdaInsideValueArgument = node.firstChildNode\n            .findChildByType(VALUE_ARGUMENT_LIST)\n            ?.findChildByType(VALUE_ARGUMENT)\n            ?.findChildByType(LAMBDA_EXPRESSION) != null\n        if (!isLambdaArgument && !isLambdaInsideValueArgument) {\n            warnRunInScript(node)\n        }\n    }\n\n    private fun warnRunInScript(node: ASTNode) {\n        RUN_IN_SCRIPT.warnAndFix(configRules, emitWarn, isFixMode, node.text, node.startOffset, node) {\n            if (node.firstChildNode.elementType != DOT_QUALIFIED_EXPRESSION) {\n                val parent = node.treeParent\n                val newNode = KotlinParser().createNode(\"run {\\n ${node.text}\\n} \\n\")\n                val newScript = CompositeElement(SCRIPT_INITIALIZER)\n                parent.addChild(newScript, node)\n                newScript.addChild(newNode)\n                parent.removeChild(node)\n            }\n        }\n    }\n\n    companion object {\n        const val NAME_ID = \"run-script\"\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/main/kotlin/com/saveourtool/diktat/ruleset/rules/chapter6/TrivialPropertyAccessors.kt",
    "content": "package com.saveourtool.diktat.ruleset.rules.chapter6\n\nimport com.saveourtool.diktat.common.config.rules.RulesConfig\nimport com.saveourtool.diktat.ruleset.constants.Warnings.TRIVIAL_ACCESSORS_ARE_NOT_RECOMMENDED\nimport com.saveourtool.diktat.ruleset.rules.DiktatRule\nimport com.saveourtool.diktat.ruleset.utils.findAllDescendantsWithSpecificType\nimport com.saveourtool.diktat.ruleset.utils.getFirstChildWithType\nimport com.saveourtool.diktat.ruleset.utils.getIdentifierName\nimport com.saveourtool.diktat.ruleset.utils.hasChildOfType\nimport com.saveourtool.diktat.ruleset.utils.isWhiteSpace\n\nimport org.jetbrains.kotlin.KtNodeTypes.BINARY_EXPRESSION\nimport org.jetbrains.kotlin.KtNodeTypes.BLOCK\nimport org.jetbrains.kotlin.KtNodeTypes.PROPERTY_ACCESSOR\nimport org.jetbrains.kotlin.KtNodeTypes.REFERENCE_EXPRESSION\nimport org.jetbrains.kotlin.KtNodeTypes.VALUE_PARAMETER_LIST\nimport org.jetbrains.kotlin.com.intellij.lang.ASTNode\nimport org.jetbrains.kotlin.lexer.KtTokens.BLOCK_COMMENT\nimport org.jetbrains.kotlin.lexer.KtTokens.EOL_COMMENT\nimport org.jetbrains.kotlin.lexer.KtTokens.LBRACE\nimport org.jetbrains.kotlin.lexer.KtTokens.RBRACE\nimport org.jetbrains.kotlin.lexer.KtTokens.WHITE_SPACE\nimport org.jetbrains.kotlin.psi.KtBinaryExpression\nimport org.jetbrains.kotlin.psi.KtPropertyAccessor\n\n/**\n * This rule checks if there are any trivial getters and setters and, if so, deletes them\n */\nclass TrivialPropertyAccessors(configRules: List<RulesConfig>) : DiktatRule(\n    NAME_ID,\n    configRules,\n    listOf(TRIVIAL_ACCESSORS_ARE_NOT_RECOMMENDED)\n) {\n    override fun logic(node: ASTNode) {\n        if (node.elementType == PROPERTY_ACCESSOR) {\n            handlePropertyAccessors(node)\n        }\n    }\n\n    private fun handlePropertyAccessors(node: ASTNode) {\n        if ((node.psi as KtPropertyAccessor).isGetter) {\n            handleGetAccessor(node)\n        } else {\n            handleSetAccessor(node)\n        }\n    }\n\n    @Suppress(\"UnsafeCallOnNullableType\")\n    private fun handleSetAccessor(node: ASTNode) {\n        val valueParamName = node\n            .getFirstChildWithType(VALUE_PARAMETER_LIST)\n            ?.firstChildNode\n            ?.getIdentifierName()\n            ?.text\n\n        if (node.hasChildOfType(BLOCK) && !valueParamName.isNullOrEmpty()) {\n            val block = node.getFirstChildWithType(BLOCK)!!\n\n            val blockChildren = block.getChildren(null).filter { it.elementType !in excessChildrenTypes }\n\n            if (blockChildren.size == 1 &&\n                    blockChildren.first().elementType == BINARY_EXPRESSION &&\n                    (blockChildren.first().psi as KtBinaryExpression).left?.text == \"field\" &&\n                    (blockChildren.first().psi as KtBinaryExpression).right?.text == valueParamName\n            ) {\n                raiseWarning(node)\n            }\n        }\n    }\n\n    @Suppress(\"UnsafeCallOnNullableType\")\n    private fun handleGetAccessor(node: ASTNode) {\n        // It handles both cases: get() = ...  and  get() { return ... }\n        val references = node.findAllDescendantsWithSpecificType(REFERENCE_EXPRESSION)\n        if (references.singleOrNull()?.text == \"field\") {\n            raiseWarning(node)\n        } else if (node.getChildren(null).size == ONE_CHILD_IN_ARRAY) {\n            raiseWarning(node)\n        }\n    }\n\n    private fun raiseWarning(node: ASTNode) {\n        TRIVIAL_ACCESSORS_ARE_NOT_RECOMMENDED.warnAndFix(configRules, emitWarn, isFixMode, node.text, node.startOffset, node) {\n            val property = (node.psi as KtPropertyAccessor).property.node\n            if (node.treePrev.isWhiteSpace()) {\n                property.removeChild(node.treePrev)\n            }\n            property.removeChild(node)\n        }\n    }\n\n    companion object {\n        const val NAME_ID = \"trivial-property-accessors\"\n        private const val ONE_CHILD_IN_ARRAY = 1\n        private val excessChildrenTypes = listOf(LBRACE, RBRACE, WHITE_SPACE, EOL_COMMENT, BLOCK_COMMENT)\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/main/kotlin/com/saveourtool/diktat/ruleset/rules/chapter6/UseLastIndex.kt",
    "content": "package com.saveourtool.diktat.ruleset.rules.chapter6\n\nimport com.saveourtool.diktat.common.config.rules.RulesConfig\nimport com.saveourtool.diktat.ruleset.constants.Warnings\nimport com.saveourtool.diktat.ruleset.rules.DiktatRule\nimport com.saveourtool.diktat.ruleset.utils.*\n\nimport org.jetbrains.kotlin.KtNodeTypes.BINARY_EXPRESSION\nimport org.jetbrains.kotlin.KtNodeTypes.DOT_QUALIFIED_EXPRESSION\nimport org.jetbrains.kotlin.KtNodeTypes.INTEGER_CONSTANT\nimport org.jetbrains.kotlin.KtNodeTypes.OPERATION_REFERENCE\nimport org.jetbrains.kotlin.KtNodeTypes.REFERENCE_EXPRESSION\nimport org.jetbrains.kotlin.com.intellij.lang.ASTNode\nimport org.jetbrains.kotlin.psi.psiUtil.children\n\n/**\n * This rule checks if there use property length with operation - 1 and fix this on lastIndex\n */\nclass UseLastIndex(configRules: List<RulesConfig>) : DiktatRule(\n    NAME_ID,\n    configRules,\n    listOf(Warnings.USE_LAST_INDEX)\n) {\n    override fun logic(node: ASTNode) {\n        if (node.elementType == BINARY_EXPRESSION) {\n            changeRight(node)\n        }\n    }\n\n    private fun changeRight(node: ASTNode) {\n        val listWithRightLength = node.children().filter {\n            val operation = node.getFirstChildWithType(OPERATION_REFERENCE)\n            val number = node.getFirstChildWithType(INTEGER_CONSTANT)\n            it.elementType == DOT_QUALIFIED_EXPRESSION && it.lastChildNode.text == \"length\" && it.lastChildNode.elementType == REFERENCE_EXPRESSION &&\n                    operation?.text == \"-\" && number?.text == \"1\"\n        }\n        if (listWithRightLength.toList().isNotEmpty()) {\n            Warnings.USE_LAST_INDEX.warnAndFix(configRules, emitWarn, isFixMode, node.text, node.startOffset, node) {\n                fix(node)\n            }\n        }\n    }\n\n    private fun fix(node: ASTNode) {\n        // A.B.length - 1 -> A.B\n        val text = node.firstChildNode.text.replace(\"length\", \"lastIndex\")\n        val parent = node.treeParent\n        val textParent = parent.text.replace(node.text, text)\n        val newParent = KotlinParser().createNode(textParent)\n        parent.treeParent.replaceChild(parent, newParent)\n    }\n\n    companion object {\n        const val NAME_ID = \"last-index\"\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/main/kotlin/com/saveourtool/diktat/ruleset/rules/chapter6/UselessSupertype.kt",
    "content": "package com.saveourtool.diktat.ruleset.rules.chapter6\n\nimport com.saveourtool.diktat.common.config.rules.RulesConfig\nimport com.saveourtool.diktat.ruleset.constants.Warnings.USELESS_SUPERTYPE\nimport com.saveourtool.diktat.ruleset.rules.DiktatRule\nimport com.saveourtool.diktat.ruleset.utils.*\nimport com.saveourtool.diktat.ruleset.utils.parent\n\nimport org.jetbrains.kotlin.KtNodeTypes.CALL_EXPRESSION\nimport org.jetbrains.kotlin.KtNodeTypes.CLASS\nimport org.jetbrains.kotlin.KtNodeTypes.CLASS_BODY\nimport org.jetbrains.kotlin.KtNodeTypes.DOT_QUALIFIED_EXPRESSION\nimport org.jetbrains.kotlin.KtNodeTypes.FUN\nimport org.jetbrains.kotlin.KtNodeTypes.MODIFIER_LIST\nimport org.jetbrains.kotlin.KtNodeTypes.REFERENCE_EXPRESSION\nimport org.jetbrains.kotlin.KtNodeTypes.SUPER_EXPRESSION\nimport org.jetbrains.kotlin.KtNodeTypes.SUPER_TYPE_CALL_ENTRY\nimport org.jetbrains.kotlin.KtNodeTypes.SUPER_TYPE_ENTRY\nimport org.jetbrains.kotlin.KtNodeTypes.SUPER_TYPE_LIST\nimport org.jetbrains.kotlin.KtNodeTypes.TYPE_REFERENCE\nimport org.jetbrains.kotlin.com.intellij.lang.ASTNode\nimport org.jetbrains.kotlin.lexer.KtTokens.CLASS_KEYWORD\nimport org.jetbrains.kotlin.lexer.KtTokens.IDENTIFIER\nimport org.jetbrains.kotlin.lexer.KtTokens.OPEN_KEYWORD\nimport org.jetbrains.kotlin.psi.psiUtil.siblings\nimport org.jetbrains.kotlin.psi.stubs.elements.KtFileElementType\n\nimport java.util.HashMap\n\n/**\n * rule 6.1.5\n * Explicit supertype qualification should not be used if there is not clash between called methods\n * fixme can't fix supertypes that are defined in other files.\n */\nclass UselessSupertype(configRules: List<RulesConfig>) : DiktatRule(\n    NAME_ID,\n    configRules,\n    listOf(USELESS_SUPERTYPE)\n) {\n    override fun logic(node: ASTNode) {\n        if (node.elementType == CLASS) {\n            checkClass(node)\n        }\n    }\n\n    private fun checkClass(node: ASTNode) {\n        val superNodes = node\n            .findChildByType(SUPER_TYPE_LIST)\n            ?.findAllNodesWithCondition { it.elementType in superType }\n            ?.takeIf { it.isNotEmpty() } ?: return\n        val qualifiedSuperCalls = node\n            .findAllDescendantsWithSpecificType(DOT_QUALIFIED_EXPRESSION)\n            .mapNotNull { findFunWithSuper(it) }\n            .ifEmpty { return }\n        if (superNodes.size == 1) {\n            qualifiedSuperCalls.map { removeSupertype(it.first) }\n        } else {\n            handleManyImpl(superNodes, qualifiedSuperCalls)\n        }\n    }\n\n    @Suppress(\"TYPE_ALIAS\")\n    private fun handleManyImpl(superNodes: List<ASTNode>, overrideNodes: List<Pair<ASTNode, ASTNode>>) {\n        val uselessSuperType = findAllSupers(superNodes, overrideNodes.map { it.second.text })\n            ?.filter { it.value == 1 }  // filtering methods whose names occur only once\n            ?.map { it.key }  // take their names\n            ?: return\n        overrideNodes\n            .filter {\n                it.second.text in uselessSuperType\n            }.map {\n                removeSupertype(it.first)\n            }\n    }\n\n    @Suppress(\"UnsafeCallOnNullableType\")\n    private fun removeSupertype(node: ASTNode) {\n        USELESS_SUPERTYPE.warnAndFix(configRules, emitWarn, isFixMode, node.text, node.startOffset, node) {\n            val startNode = node.parent { it.elementType == SUPER_EXPRESSION }!!.findChildByType(REFERENCE_EXPRESSION)!!\n            val lastNode = startNode.siblings(true).last()\n            startNode.treeParent.removeRange(startNode.treeNext, lastNode)\n            startNode.treeParent.removeChild(lastNode)\n        }\n    }\n\n    /**\n     * Method finds pair of identifier supertype and method name else return null\n     * example: super<A>.foo() -> return Pair(A, foo)\n     *          super.foo() -> null\n     *\n     * @param node - node of type DOT_QUALIFIED_EXPRESSION\n     * @return pair of identifier\n     */\n    @Suppress(\"UnsafeCallOnNullableType\", \"WRONG_NEWLINES\")\n    private fun findFunWithSuper(node: ASTNode) = Pair(\n        node.findChildByType(SUPER_EXPRESSION)\n            ?.findChildByType(TYPE_REFERENCE)\n            ?.findAllDescendantsWithSpecificType(IDENTIFIER)\n            ?.firstOrNull(),\n        node.findChildByType(CALL_EXPRESSION)\n            ?.findAllDescendantsWithSpecificType(IDENTIFIER)\n            ?.firstOrNull())\n        .run {\n            if (first == null || second == null) null else first!! to second!!\n        }\n\n    /**\n     * The method looks in the same file for all super interfaces or a class, in each it looks for methods\n     * that can be overridden and creates a map with a key - the name of the method and value - the number of times it meets\n     *\n     * @param superTypeList - list of identifiers super classes\n     * @param methodsName - name of overrides methods\n     * @return map name of method and the number of times it meets\n     */\n    @Suppress(\"UnsafeCallOnNullableType\", \"WRONG_NEWLINES\")\n    private fun findAllSupers(superTypeList: List<ASTNode>, methodsName: List<String>): Map<String, Int>? {\n        val fileNode = superTypeList.first().parent { it.elementType == KtFileElementType.INSTANCE }!!\n        val superNodesIdentifier = superTypeList.map {\n            it.findAllDescendantsWithSpecificType(IDENTIFIER)\n                .first()\n                .text\n        }\n        val superNodes = fileNode.findAllNodesWithCondition { superClass ->\n            superClass.elementType == CLASS &&\n                    superClass.getIdentifierName()!!.text in superNodesIdentifier\n        }.mapNotNull { it.findChildByType(CLASS_BODY) }\n        if (superNodes.size != superTypeList.size) {\n            return null\n        }\n        val functionNameMap: HashMap<String, Int> = hashMapOf()\n        superNodes.forEach { classBody ->\n            val overrideFunctions = classBody.findAllDescendantsWithSpecificType(FUN)\n                .filter {\n                    (if (classBody.treeParent.hasChildOfType(CLASS_KEYWORD)) it.findChildByType(MODIFIER_LIST)!!.hasChildOfType(OPEN_KEYWORD) else true) &&\n                            it.getIdentifierName()!!.text in methodsName\n                }\n            @Suppress(\"PARAMETER_NAME_IN_OUTER_LAMBDA\")\n            overrideFunctions.forEach {\n                functionNameMap.compute(it.getIdentifierName()!!.text) { _, oldValue -> (oldValue ?: 0) + 1 }\n            }\n        }\n        return functionNameMap.toMap()\n    }\n\n    companion object {\n        const val NAME_ID = \"useless-override\"\n        private val superType = listOf(SUPER_TYPE_CALL_ENTRY, SUPER_TYPE_ENTRY)\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/main/kotlin/com/saveourtool/diktat/ruleset/rules/chapter6/classes/AbstractClassesRule.kt",
    "content": "package com.saveourtool.diktat.ruleset.rules.chapter6.classes\n\nimport com.saveourtool.diktat.common.config.rules.RulesConfig\nimport com.saveourtool.diktat.ruleset.constants.Warnings.CLASS_SHOULD_NOT_BE_ABSTRACT\nimport com.saveourtool.diktat.ruleset.rules.DiktatRule\nimport com.saveourtool.diktat.ruleset.utils.getAllChildrenWithType\nimport com.saveourtool.diktat.ruleset.utils.getFirstChildWithType\nimport com.saveourtool.diktat.ruleset.utils.hasChildOfType\n\nimport org.jetbrains.kotlin.KtNodeTypes.CLASS\nimport org.jetbrains.kotlin.KtNodeTypes.CLASS_BODY\nimport org.jetbrains.kotlin.KtNodeTypes.FUN\nimport org.jetbrains.kotlin.KtNodeTypes.MODIFIER_LIST\nimport org.jetbrains.kotlin.KtNodeTypes.PROPERTY\nimport org.jetbrains.kotlin.KtNodeTypes.SUPER_TYPE_CALL_ENTRY\nimport org.jetbrains.kotlin.KtNodeTypes.SUPER_TYPE_ENTRY\nimport org.jetbrains.kotlin.KtNodeTypes.SUPER_TYPE_LIST\nimport org.jetbrains.kotlin.com.intellij.lang.ASTNode\nimport org.jetbrains.kotlin.com.intellij.psi.impl.source.tree.LeafPsiElement\nimport org.jetbrains.kotlin.lexer.KtTokens.ABSTRACT_KEYWORD\nimport org.jetbrains.kotlin.lexer.KtTokens.IDENTIFIER\nimport org.jetbrains.kotlin.lexer.KtTokens.OPEN_KEYWORD\nimport org.jetbrains.kotlin.psi.psiUtil.children\n\n/**\n * Checks if abstract class has any abstract method. If not, warns that class should not be abstract\n */\nclass AbstractClassesRule(configRules: List<RulesConfig>) : DiktatRule(\n    NAME_ID,\n    configRules,\n    listOf(CLASS_SHOULD_NOT_BE_ABSTRACT)\n) {\n    override fun logic(node: ASTNode) {\n        if (node.elementType == CLASS) {\n            val classBody = node.getFirstChildWithType(CLASS_BODY) ?: return\n\n            // If an abstract class extends another class, than that base class can be abstract too.\n            // Then this class must have `abstract` modifier even if it doesn't have any abstract members.\n            // Class also can have `abstract` modifier if it implements interface\n            if (node.hasAbstractModifier() && node.isNotSubclass()) {\n                handleAbstractClass(classBody, node)\n            }\n        }\n    }\n\n    private fun ASTNode.hasAbstractModifier(): Boolean =\n        getFirstChildWithType(MODIFIER_LIST)?.hasChildOfType(ABSTRACT_KEYWORD) ?: false\n\n    private fun ASTNode.isNotSubclass(): Boolean = findChildByType(SUPER_TYPE_LIST)?.children()?.filter {\n        it.elementType == SUPER_TYPE_CALL_ENTRY || it.elementType == SUPER_TYPE_ENTRY\n    }?.none() ?: true\n\n    @Suppress(\"UnsafeCallOnNullableType\")\n    private fun handleAbstractClass(node: ASTNode, classNode: ASTNode) {\n        val functions = node.getAllChildrenWithType(FUN)\n        val properties = node.getAllChildrenWithType(PROPERTY)\n        val members = functions + properties\n\n        val identifier = classNode.getFirstChildWithType(IDENTIFIER)!!.text\n\n        if (members.isNotEmpty() && members.none { it.hasAbstractModifier() }) {\n            CLASS_SHOULD_NOT_BE_ABSTRACT.warnAndFix(configRules, emitWarn, isFixMode, identifier, node.startOffset, node) {\n                val modList = classNode.getFirstChildWithType(MODIFIER_LIST)!!\n                val abstractKeyword = modList.getFirstChildWithType(ABSTRACT_KEYWORD)!!\n                val newOpenKeyword = LeafPsiElement(OPEN_KEYWORD, \"open\")\n                modList.replaceChild(abstractKeyword, newOpenKeyword)\n            }\n        }\n    }\n\n    companion object {\n        const val NAME_ID = \"abstract-classes\"\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/main/kotlin/com/saveourtool/diktat/ruleset/rules/chapter6/classes/CompactInitialization.kt",
    "content": "package com.saveourtool.diktat.ruleset.rules.chapter6.classes\n\nimport com.saveourtool.diktat.common.config.rules.RulesConfig\nimport com.saveourtool.diktat.ruleset.constants.Warnings.COMPACT_OBJECT_INITIALIZATION\nimport com.saveourtool.diktat.ruleset.rules.DiktatRule\nimport com.saveourtool.diktat.ruleset.utils.KotlinParser\nimport com.saveourtool.diktat.ruleset.utils.findAllDescendantsWithSpecificType\nimport com.saveourtool.diktat.ruleset.utils.findLeafWithSpecificType\nimport com.saveourtool.diktat.ruleset.utils.getFunctionName\nimport com.saveourtool.diktat.ruleset.utils.isPartOfComment\n\nimport io.github.oshai.kotlinlogging.KotlinLogging\nimport org.jetbrains.kotlin.KtNodeTypes.CALL_EXPRESSION\nimport org.jetbrains.kotlin.KtNodeTypes.OPERATION_REFERENCE\nimport org.jetbrains.kotlin.KtNodeTypes.REFERENCE_EXPRESSION\nimport org.jetbrains.kotlin.com.intellij.lang.ASTNode\nimport org.jetbrains.kotlin.com.intellij.psi.PsiWhiteSpace\nimport org.jetbrains.kotlin.kdoc.lexer.KDocTokens.KDOC\nimport org.jetbrains.kotlin.lexer.KtTokens.BLOCK_COMMENT\nimport org.jetbrains.kotlin.lexer.KtTokens.EOL_COMMENT\nimport org.jetbrains.kotlin.lexer.KtTokens.EQ\nimport org.jetbrains.kotlin.lexer.KtTokens.LBRACE\nimport org.jetbrains.kotlin.lexer.KtTokens.THIS_KEYWORD\nimport org.jetbrains.kotlin.lexer.KtTokens.WHITE_SPACE\nimport org.jetbrains.kotlin.psi.KtBinaryExpression\nimport org.jetbrains.kotlin.psi.KtCallExpression\nimport org.jetbrains.kotlin.psi.KtCallableReferenceExpression\nimport org.jetbrains.kotlin.psi.KtDotQualifiedExpression\nimport org.jetbrains.kotlin.psi.KtNameReferenceExpression\nimport org.jetbrains.kotlin.psi.KtParenthesizedExpression\nimport org.jetbrains.kotlin.psi.KtProperty\nimport org.jetbrains.kotlin.psi.KtQualifiedExpression\nimport org.jetbrains.kotlin.psi.KtReferenceExpression\nimport org.jetbrains.kotlin.psi.psiUtil.siblings\nimport org.jetbrains.kotlin.psi.psiUtil.startOffset\n\n/**\n * This rules checks if an object initialization can be wrapped into an `apply` function.\n * This is useful for classes that, e.g. have single constructor without parameters and setters for all the parameters.\n * FixMe: When assigned variable's name is also a `this@apply`'s property, it should be changed to qualified name,\n *  e.g `this@Foo`. But for this we need a mechanism to determine declaration scope and it's label.\n */\nclass CompactInitialization(configRules: List<RulesConfig>) : DiktatRule(\n    NAME_ID,\n    configRules,\n    listOf(COMPACT_OBJECT_INITIALIZATION)\n) {\n    private val kotlinParser by lazy { KotlinParser() }\n\n    override fun logic(node: ASTNode) {\n        node\n            .psi\n            .let { it as? KtProperty }\n            ?.takeIf { it.hasInitializer() }\n            ?.let(::handleProperty)\n    }\n\n    /**\n     * Check property's initializer: if it is a method call, we find all consecutive statements that are this property's\n     * fields accessors and wrap them in an `apply` function.\n     */\n    @Suppress(\"UnsafeCallOnNullableType\", \"PARAMETER_NAME_IN_OUTER_LAMBDA\")\n    private fun handleProperty(property: KtProperty) {\n        property.run {\n            val propertyName = name\n            siblings(forward = true, withItself = false)\n                .filterNot { it.node.isPartOfComment() || it is PsiWhiteSpace }\n                .takeWhile {\n                    // statements like `name.field = value` where name == propertyName\n                    it is KtBinaryExpression && it.node.findChildByType(OPERATION_REFERENCE)?.findChildByType(EQ) != null &&\n                            (it.left as? KtDotQualifiedExpression)?.run {\n                                (receiverExpression as? KtNameReferenceExpression)?.getReferencedName() == propertyName\n                            }\n                            ?: false\n                }\n                .map {\n                    // collect as an assignment associated with assigned field name\n                    it as KtBinaryExpression to (it.left as KtDotQualifiedExpression).selectorExpression!!\n                }\n        }\n            .filter { (assignment, _) ->\n                assignment.node.findLeafWithSpecificType(THIS_KEYWORD) == null\n            }\n            .toList()\n            .forEach { (assignment, field) ->\n                COMPACT_OBJECT_INITIALIZATION.warnAndFix(\n                    configRules, emitWarn, isFixMode,\n                    field.text, assignment.startOffset, assignment.node\n                ) {\n                    moveAssignmentIntoApply(property, assignment)\n                }\n            }\n    }\n\n    @Suppress(\n        \"UnsafeCallOnNullableType\",\n        \"NestedBlockDepth\",\n        \"TOO_LONG_FUNCTION\"\n    )\n    private fun moveAssignmentIntoApply(property: KtProperty, assignment: KtBinaryExpression) {\n        // get apply expression or create empty; convert `apply(::foo)` to `apply { foo(this) }` if necessary\n        getOrCreateApplyBlock(property).let(::convertValueParametersToLambdaArgument)\n        // apply expression can have been changed earlier, so we need to get it once again\n        with(getOrCreateApplyBlock(property)) {\n            lambdaArguments\n                .single()\n                // KtLambdaArgument#getArgumentExpression is Nullable IfNotParsed\n                .getLambdaExpression()!!\n                .run {\n                    val bodyExpression = functionLiteral\n                        // note: we are dealing with function literal: braces belong to KtFunctionLiteral,\n                        // but it's body is a KtBlockExpression, which therefore doesn't have braces\n                        .bodyExpression!!\n                        .node\n                    // move comments and empty lines before `assignment` into `apply`\n                    assignment\n                        .node\n                        .siblings(forward = false)\n                        .takeWhile { it.elementType in listOf(WHITE_SPACE, EOL_COMMENT, BLOCK_COMMENT, KDOC) }\n                        .toList()\n                        .reversed()\n                        .forEachIndexed { index, it ->\n                            // adds whiteSpace to functional literal if previous of bodyExpression is LBRACE\n                            if (index == 0 && bodyExpression.treePrev.elementType == LBRACE && it.elementType == WHITE_SPACE) {\n                                bodyExpression.treeParent.addChild(it.clone() as ASTNode, bodyExpression)\n                            } else {\n                                bodyExpression.addChild(it.clone() as ASTNode, null)\n                            }\n                            it.treeParent.removeChild(it)\n                        }\n                    val receiverName = (assignment.left as KtDotQualifiedExpression).receiverExpression\n                    // looking for usages of receiver in right part\n                    val identifiers = assignment.right!!.node.findAllDescendantsWithSpecificType(REFERENCE_EXPRESSION)\n                    identifiers.forEach {\n                        if (it.text == receiverName.text && it.treeParent.elementType != CALL_EXPRESSION) {\n                            it.treeParent.replaceChild(it, kotlinParser.createNode(\"this\"))\n                        }\n                    }\n                    // strip receiver name and move assignment itself into `apply`\n                    bodyExpression.addChild(kotlinParser.createNode(assignment.text.substringAfter('.')), null)\n                    assignment.node.run { treeParent.removeChild(this) }\n                }\n        }\n    }\n\n    @Suppress(\"UnsafeCallOnNullableType\")\n    private fun getOrCreateApplyBlock(property: KtProperty): KtCallExpression = (property.initializer as? KtDotQualifiedExpression)\n        ?.selectorExpression\n        ?.let { it as? KtCallExpression }\n        ?.takeIf { it.getFunctionName() == \"apply\" }\n        ?: run {\n            // add apply block\n            property.node.run {\n                val newInitializerNodeText = buildInitializerNodeText(property)\n                val newInitializerNode = kotlinParser.createNode(newInitializerNodeText)\n                replaceChild(property.initializer!!.node, newInitializerNode)\n            }\n            (property.initializer as KtDotQualifiedExpression).selectorExpression!! as KtCallExpression\n        }\n\n    @Suppress(\"UnsafeCallOnNullableType\")\n    private fun buildInitializerNodeText(property: KtProperty): String {\n        val isRequiresParentheses = property.initializer.let {\n            // list of expression types, that can be directly followed by a dot-qualified call\n            // e.g. val x = foo()  ->  val x = foo().apply {}\n            // e.g. val x = foo + bar  ->  val x = (foo + bar).apply {}\n            it is KtParenthesizedExpression || it is KtQualifiedExpression || it is KtReferenceExpression\n        }.not()\n        return buildString {\n            if (isRequiresParentheses) {\n                append(\"(\")\n            }\n            append(property.initializer!!.text)\n            if (isRequiresParentheses) {\n                append(\")\")\n            }\n            append(\".apply {}\")\n        }\n    }\n\n    /**\n     * convert `apply(::foo)` to `apply { foo(this) }` if necessary\n     */\n    private fun convertValueParametersToLambdaArgument(applyExpression: KtCallExpression) {\n        if (applyExpression.lambdaArguments.isEmpty()) {\n            val referenceExpression = applyExpression\n                .valueArguments\n                .singleOrNull()\n                ?.getArgumentExpression()\n                ?.let { it as? KtCallableReferenceExpression }\n                ?.callableReference\n            referenceExpression?.let {\n                applyExpression.node.run {\n                    treeParent.replaceChild(\n                        this,\n                        kotlinParser.createNode(\n                            \"\"\"\n                                |apply {\n                                |    ${referenceExpression.getReferencedName()}(this)\n                                |}\n                            \"\"\".trimMargin()\n                        )\n                    )\n                }\n            }\n                ?: run {\n                    // valid code should always have apply with either lambdaArguments or valueArguments\n                    log.warn { \"apply with unexpected parameters: ${applyExpression.text}\" }\n                }\n        }\n    }\n\n    companion object {\n        private val log = KotlinLogging.logger {}\n        const val NAME_ID = \"class-compact-initialization\"\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/main/kotlin/com/saveourtool/diktat/ruleset/rules/chapter6/classes/DataClassesRule.kt",
    "content": "package com.saveourtool.diktat.ruleset.rules.chapter6.classes\n\nimport com.saveourtool.diktat.common.config.rules.RulesConfig\nimport com.saveourtool.diktat.ruleset.constants.Warnings.USE_DATA_CLASS\nimport com.saveourtool.diktat.ruleset.rules.DiktatRule\nimport com.saveourtool.diktat.ruleset.utils.*\n\nimport org.jetbrains.kotlin.KtNodeTypes.BLOCK\nimport org.jetbrains.kotlin.KtNodeTypes.CLASS\nimport org.jetbrains.kotlin.KtNodeTypes.CLASS_BODY\nimport org.jetbrains.kotlin.KtNodeTypes.CLASS_INITIALIZER\nimport org.jetbrains.kotlin.KtNodeTypes.FUN\nimport org.jetbrains.kotlin.KtNodeTypes.MODIFIER_LIST\nimport org.jetbrains.kotlin.KtNodeTypes.PRIMARY_CONSTRUCTOR\nimport org.jetbrains.kotlin.KtNodeTypes.PROPERTY\nimport org.jetbrains.kotlin.KtNodeTypes.PROPERTY_ACCESSOR\nimport org.jetbrains.kotlin.KtNodeTypes.REFERENCE_EXPRESSION\nimport org.jetbrains.kotlin.KtNodeTypes.SUPER_TYPE_LIST\nimport org.jetbrains.kotlin.com.intellij.lang.ASTNode\nimport org.jetbrains.kotlin.lexer.KtTokens.OPEN_KEYWORD\nimport org.jetbrains.kotlin.psi.KtClass\nimport org.jetbrains.kotlin.psi.KtClassBody\nimport org.jetbrains.kotlin.psi.KtExpression\nimport org.jetbrains.kotlin.psi.KtPrimaryConstructor\nimport org.jetbrains.kotlin.psi.psiUtil.isAbstract\n\n/**\n * This rule checks if class can be made as data class\n */\nclass DataClassesRule(configRules: List<RulesConfig>) : DiktatRule(\n    NAME_ID,\n    configRules,\n    listOf(USE_DATA_CLASS)\n) {\n    override fun logic(node: ASTNode) {\n        if (node.elementType == CLASS) {\n            handleClass(node)\n        }\n    }\n\n    private fun handleClass(node: ASTNode) {\n        if ((node.psi as KtClass).isDefinitelyNotDataClass()) {\n            return\n        }\n\n        if (node.canBeDataClass()) {\n            raiseWarn(node)\n        }\n    }\n\n    // fixme: Need to know types of vars and props to create data class\n    private fun raiseWarn(node: ASTNode) {\n        USE_DATA_CLASS.warn(configRules, emitWarn, \"${(node.psi as KtClass).name}\", node.startOffset, node)\n    }\n\n    @Suppress(\n        \"UnsafeCallOnNullableType\",\n        \"FUNCTION_BOOLEAN_PREFIX\",\n        \"ComplexMethod\"\n    )\n    private fun ASTNode.canBeDataClass(): Boolean {\n        val isNotPropertyInClassBody = findChildByType(CLASS_BODY)?.let { (it.psi as KtClassBody).properties.isEmpty() } ?: true\n        val constructorParametersNames: MutableList<String> = mutableListOf()\n        val hasPropertyInConstructor = findChildByType(PRIMARY_CONSTRUCTOR)\n            ?.let { constructor ->\n                (constructor.psi as KtPrimaryConstructor)\n                    .valueParameters\n                    .onEach {\n                        if (!it.hasValOrVar()) {\n                            constructorParametersNames.add(it.name!!)\n                        }\n                    }\n                    .run { isNotEmpty() && all { it.hasValOrVar() } }\n            } ?: false\n        if (isNotPropertyInClassBody && !hasPropertyInConstructor) {\n            return false\n        }\n        // if parameter of the primary constructor is used in init block then it is hard to refactor this class to data class\n        if (constructorParametersNames.isNotEmpty()) {\n            val initBlocks = findChildByType(CLASS_BODY)?.getAllChildrenWithType(CLASS_INITIALIZER)\n            initBlocks?.forEach { init ->\n                val refExpressions = init.findAllDescendantsWithSpecificType(REFERENCE_EXPRESSION)\n                if (refExpressions.any { it.text in constructorParametersNames }) {\n                    return false\n                }\n            }\n        }\n        return hasAppropriateClassBody()\n    }\n\n    @Suppress(\"UnsafeCallOnNullableType\")\n    private fun ASTNode.hasAppropriateClassBody(): Boolean {\n        val classBody = getFirstChildWithType(CLASS_BODY)\n        if (hasChildOfType(MODIFIER_LIST)) {\n            val list = getFirstChildWithType(MODIFIER_LIST)!!\n            return list.getChildren(null)\n                .none { it.elementType in badModifiers } &&\n                    classBody?.getAllChildrenWithType(FUN)\n                        ?.isEmpty()\n                    ?: false &&\n                    getFirstChildWithType(SUPER_TYPE_LIST) == null\n        }\n        return classBody?.getFirstChildWithType(FUN) == null &&\n                getFirstChildWithType(SUPER_TYPE_LIST) == null &&\n                // if there is any prop with logic in accessor then don't recommend to convert class to data class\n                classBody?.let(::areGoodProps)\n                ?: true\n    }\n\n    /**\n     * Checks if any property with accessor contains logic in accessor\n     */\n    private fun areGoodProps(node: ASTNode): Boolean {\n        val propertiesWithAccessors = node.getAllChildrenWithType(PROPERTY).filter { it.hasChildOfType(PROPERTY_ACCESSOR) }\n\n        if (propertiesWithAccessors.isNotEmpty()) {\n            return propertiesWithAccessors.any {\n                val accessors = it.getAllChildrenWithType(PROPERTY_ACCESSOR)\n\n                areGoodAccessors(accessors)\n            }\n        }\n\n        return true\n    }\n\n    /**\n     * We do not exclude inner classes here as if they have no\n     * methods, then we definitely can refactor the code and make them data classes.\n     * We only exclude: value/inline classes, enums, annotations, interfaces, abstract classes,\n     * sealed classes and data classes itself. For sure there will be other corner cases,\n     * for example, simple classes in Spring marked with @Entity annotation.\n     * For these classes we expect users to Suppress warning manually for each corner case.\n     **/\n    private fun KtClass.isDefinitelyNotDataClass() =\n        isValue() || isAnnotation() || isInterface() || isData() ||\n                isSealed() || isInline() || isAbstract() || isEnum()\n\n    @Suppress(\"UnsafeCallOnNullableType\", \"PARAMETER_NAME_IN_OUTER_LAMBDA\")\n    private fun areGoodAccessors(accessors: List<ASTNode>): Boolean {\n        accessors.forEach {\n            if (it.hasChildOfType(BLOCK)) {\n                val block = it.getFirstChildWithType(BLOCK)!!\n\n                return block\n                    .getChildren(null)\n                    .count { expr -> expr.psi is KtExpression } <= 1\n            }\n        }\n\n        return true\n    }\n\n    companion object {\n        const val NAME_ID = \"data-classes\"\n        private val badModifiers = listOf(OPEN_KEYWORD)\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/main/kotlin/com/saveourtool/diktat/ruleset/rules/chapter6/classes/InlineClassesRule.kt",
    "content": "package com.saveourtool.diktat.ruleset.rules.chapter6.classes\n\nimport com.saveourtool.diktat.common.config.rules.RulesConfig\nimport com.saveourtool.diktat.common.config.rules.getCommonConfiguration\nimport com.saveourtool.diktat.ruleset.constants.Warnings.INLINE_CLASS_CAN_BE_USED\nimport com.saveourtool.diktat.ruleset.rules.DiktatRule\nimport com.saveourtool.diktat.ruleset.utils.getFirstChildWithType\nimport com.saveourtool.diktat.ruleset.utils.hasChildOfType\n\nimport org.jetbrains.kotlin.KtNodeTypes.CLASS\nimport org.jetbrains.kotlin.KtNodeTypes.CONSTRUCTOR_CALLEE\nimport org.jetbrains.kotlin.KtNodeTypes.MODIFIER_LIST\nimport org.jetbrains.kotlin.KtNodeTypes.SUPER_TYPE_LIST\nimport org.jetbrains.kotlin.com.intellij.lang.ASTNode\nimport org.jetbrains.kotlin.lexer.KtTokens.FINAL_KEYWORD\nimport org.jetbrains.kotlin.lexer.KtTokens.INTERNAL_KEYWORD\nimport org.jetbrains.kotlin.lexer.KtTokens.PRIVATE_KEYWORD\nimport org.jetbrains.kotlin.lexer.KtTokens.PROTECTED_KEYWORD\nimport org.jetbrains.kotlin.lexer.KtTokens.PUBLIC_KEYWORD\nimport org.jetbrains.kotlin.lexer.KtTokens.VAR_KEYWORD\nimport org.jetbrains.kotlin.psi.KtClass\nimport org.jetbrains.kotlin.psi.psiUtil.children\nimport org.jetbrains.kotlin.psi.psiUtil.visibilityModifierType\n\n/**\n * This rule checks if inline class can be used.\n */\nclass InlineClassesRule(configRules: List<RulesConfig>) : DiktatRule(\n    NAME_ID,\n    configRules,\n    listOf(INLINE_CLASS_CAN_BE_USED)\n) {\n    override fun logic(node: ASTNode) {\n        val configuration = configRules.getCommonConfiguration()\n        if (node.elementType == CLASS &&\n                !(node.psi as KtClass).isInterface() &&\n                configuration.kotlinVersion >= minKtVersion &&\n                configuration.kotlinVersion < maxKtVersion\n        ) {\n            handleClasses(node.psi as KtClass)\n        }\n    }\n\n    private fun handleClasses(classPsi: KtClass) {\n        // Fixme: In Kotlin 1.4.30 inline classes may be used with internal constructors. When it will be released need to check it\n        if (hasValidProperties(classPsi) &&\n                !isExtendingClass(classPsi.node) &&\n                classPsi.node\n                    .getFirstChildWithType(MODIFIER_LIST)\n                    ?.getChildren(null)\n                    ?.all { it.elementType in goodModifiers } != false) {\n            // Fixme: since it's an experimental feature we shouldn't do fixer\n            INLINE_CLASS_CAN_BE_USED.warn(configRules, emitWarn, \"class ${classPsi.name}\", classPsi.node.startOffset, classPsi.node)\n        }\n    }\n\n    private fun hasValidProperties(classPsi: KtClass): Boolean {\n        if (classPsi.getProperties().size == 1 && !classPsi.hasExplicitPrimaryConstructor()) {\n            return !classPsi.getProperties().single().isVar\n        } else if (classPsi.getProperties().isEmpty() && classPsi.hasExplicitPrimaryConstructor()) {\n            return classPsi.primaryConstructorParameters.size == 1 &&\n                    !classPsi.primaryConstructorParameters\n                        .first()\n                        .node\n                        .hasChildOfType(VAR_KEYWORD) &&\n                    classPsi.primaryConstructor\n                        ?.visibilityModifierType()\n                        ?.value\n                        ?.let { it == \"public\" } ?: true\n        }\n        return false\n    }\n\n    private fun isExtendingClass(node: ASTNode): Boolean =\n        node\n            .getFirstChildWithType(SUPER_TYPE_LIST)\n            ?.children()\n            ?.any { it.hasChildOfType(CONSTRUCTOR_CALLEE) }\n            ?: false\n\n    companion object {\n        const val NAME_ID = \"inline-classes\"\n        val minKtVersion = KotlinVersion(1, 3)\n        val maxKtVersion = KotlinVersion(1, 5, 0)\n        val goodModifiers = listOf(PUBLIC_KEYWORD, PRIVATE_KEYWORD, FINAL_KEYWORD, PROTECTED_KEYWORD, INTERNAL_KEYWORD)\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/main/kotlin/com/saveourtool/diktat/ruleset/rules/chapter6/classes/SingleConstructorRule.kt",
    "content": "package com.saveourtool.diktat.ruleset.rules.chapter6.classes\n\nimport com.saveourtool.diktat.common.config.rules.RulesConfig\nimport com.saveourtool.diktat.ruleset.constants.Warnings.SINGLE_CONSTRUCTOR_SHOULD_BE_PRIMARY\nimport com.saveourtool.diktat.ruleset.rules.DiktatRule\nimport com.saveourtool.diktat.ruleset.utils.KotlinParser\nimport com.saveourtool.diktat.ruleset.utils.findChildrenMatching\nimport com.saveourtool.diktat.ruleset.utils.getAllChildrenWithType\nimport com.saveourtool.diktat.ruleset.utils.getIdentifierName\nimport com.saveourtool.diktat.ruleset.utils.hasChildOfType\nimport com.saveourtool.diktat.ruleset.utils.isGoingAfter\nimport com.saveourtool.diktat.ruleset.utils.nextCodeSibling\n\nimport org.jetbrains.kotlin.KtNodeTypes.CLASS\nimport org.jetbrains.kotlin.KtNodeTypes.CLASS_BODY\nimport org.jetbrains.kotlin.KtNodeTypes.MODIFIER_LIST\nimport org.jetbrains.kotlin.KtNodeTypes.PRIMARY_CONSTRUCTOR\nimport org.jetbrains.kotlin.KtNodeTypes.SECONDARY_CONSTRUCTOR\nimport org.jetbrains.kotlin.com.intellij.lang.ASTNode\nimport org.jetbrains.kotlin.com.intellij.psi.impl.source.tree.PsiWhiteSpaceImpl\nimport org.jetbrains.kotlin.kdoc.lexer.KDocTokens.KDOC\nimport org.jetbrains.kotlin.lexer.KtTokens.BLOCK_COMMENT\nimport org.jetbrains.kotlin.lexer.KtTokens.EOL_COMMENT\nimport org.jetbrains.kotlin.lexer.KtTokens.WHITE_SPACE\nimport org.jetbrains.kotlin.psi.KtBinaryExpression\nimport org.jetbrains.kotlin.psi.KtClass\nimport org.jetbrains.kotlin.psi.KtDotQualifiedExpression\nimport org.jetbrains.kotlin.psi.KtExpression\nimport org.jetbrains.kotlin.psi.KtNameReferenceExpression\nimport org.jetbrains.kotlin.psi.KtParameter\nimport org.jetbrains.kotlin.psi.KtProperty\nimport org.jetbrains.kotlin.psi.KtSecondaryConstructor\nimport org.jetbrains.kotlin.psi.KtThisExpression\nimport org.jetbrains.kotlin.psi.psiUtil.asAssignment\nimport org.jetbrains.kotlin.psi.psiUtil.collectDescendantsOfType\n\n/**\n * This rule ensures that if a class has a single constructor, this constructor is primary.\n * Secondary constructor is converted into primary, statements that are not assignments are moved into an `init` block.\n */\nclass SingleConstructorRule(configRules: List<RulesConfig>) : DiktatRule(\n    NAME_ID,\n    configRules,\n    listOf(SINGLE_CONSTRUCTOR_SHOULD_BE_PRIMARY)\n) {\n    private val kotlinParser by lazy { KotlinParser() }\n\n    override fun logic(node: ASTNode) {\n        if (node.elementType == CLASS) {\n            handleClassConstructors(node)\n        }\n    }\n\n    private fun handleClassConstructors(node: ASTNode) {\n        if (!node.hasChildOfType(PRIMARY_CONSTRUCTOR)) {\n            // class has no primary constructor, need to count secondary constructors\n            node\n                .findChildByType(CLASS_BODY)\n                ?.getAllChildrenWithType(SECONDARY_CONSTRUCTOR)\n                ?.singleOrNull()\n                ?.let { secondaryCtor ->\n                    SINGLE_CONSTRUCTOR_SHOULD_BE_PRIMARY.warnAndFix(\n                        configRules, emitWarn, isFixMode, \"in class <${node.getIdentifierName()?.text}>\",\n                        node.startOffset, node\n                    ) {\n                        convertConstructorToPrimary(node, secondaryCtor)\n                    }\n                }\n        }\n    }\n\n    /**\n     * This method does the following:\n     * - Inside the single secondary constructor find all assignments.\n     * - Some of assigned values will have `this` qualifier, they are definitely class properties.\n     * - For other assigned variables that are not declared in the same scope we check if they are properties and whether they depend only on constructor parameters.\n     * - Create primary constructor moving all properties that we collected.\n     * - Create init block with other statements from the secondary constructor, including initialization of properties that require local variables or complex calls.\n     * - Finally, remove the secondary constructor.\n     */\n    @Suppress(\n        \"GENERIC_VARIABLE_WRONG_DECLARATION\",\n        \"TOO_LONG_FUNCTION\"\n    )\n    private fun convertConstructorToPrimary(classNode: ASTNode, secondaryCtor: ASTNode) {\n        val secondaryCtorArguments = (secondaryCtor.psi as KtSecondaryConstructor).valueParameters\n\n        // split all statements into assignments and all other statements (including comments)\n        val (assignments, otherStatements) = (secondaryCtor.psi as KtSecondaryConstructor)\n            .bodyBlockExpression\n            ?.statements\n            ?.partition { it is KtBinaryExpression && it.asAssignment() != null }\n            ?.run { first.map { it as KtBinaryExpression } to second }\n            ?: (emptyList<KtBinaryExpression>() to emptyList())\n\n        val comments = (secondaryCtor.psi as KtSecondaryConstructor)\n            .bodyBlockExpression\n            ?.findChildrenMatching { it.elementType == EOL_COMMENT || it.elementType == BLOCK_COMMENT || it.elementType == KDOC }\n            ?.associate {\n                it.text to it.nextCodeSibling()\n            }\n            ?.filterValues { it != null }\n\n        val classProperties = (classNode.psi as KtClass).getProperties()\n        val localProperties = secondaryCtor.psi.collectDescendantsOfType<KtProperty> { it.isLocal }\n        // find all references to class properties that are getting assigned in a constructor\n        val assignmentsToReferences = assignments.associateWithAssignedReference(localProperties, classProperties)\n\n        // Split all assignments into trivial (that are just assigned from a constructor parameter) and non-trivial.\n        // Logic for non-trivial assignments should than be kept and moved into a dedicated `init` block.\n        val (trivialAssignments, nonTrivialAssignments) = assignmentsToReferences\n            .toList()\n            .partition { (assignment, _) ->\n                assignment.right.let { rhs ->\n                    rhs is KtNameReferenceExpression && rhs.getReferencedName() in secondaryCtorArguments.map { it.name }\n                }\n            }\n            .let { it.first.toMap() to it.second.toMap() }\n\n        // find corresponding properties' declarations\n        val declarationsAssignedInCtor = trivialAssignments\n            .mapNotNull { (_, reference) ->\n                (classNode.psi as KtClass).getProperties()\n                    .firstOrNull { it.nameIdentifier?.text == reference.getReferencedName() }\n            }\n            .distinct()\n\n        // future init body\n        val expressions = (secondaryCtor.psi as KtSecondaryConstructor)\n            .bodyBlockExpression\n            ?.statements\n            ?.map { it.text }\n            ?.filter { expr -> expr in otherStatements.map { it.text } || expr in nonTrivialAssignments.keys.map { it.text } }\n            ?: emptyList()\n\n        classNode.convertSecondaryConstructorToPrimary(secondaryCtor, declarationsAssignedInCtor, nonTrivialAssignments, otherStatements, comments, expressions)\n    }\n\n    @Suppress(\"UnsafeCallOnNullableType\")\n    private fun List<KtBinaryExpression>.associateWithAssignedReference(localProperties: List<KtProperty>, classProperties: List<KtProperty>) =\n        associateWith {\n            // non-null assert is safe because of predicate in partitioning\n            it.asAssignment()!!.left!!\n        }\n            .filterValues { left ->\n                // we keep only statements where property is referenced via this (like `this.foo = ...`)\n                left is KtDotQualifiedExpression && left.receiverExpression is KtThisExpression && left.selectorExpression is KtNameReferenceExpression ||\n                        // or directly (like `foo = ...`)\n                        left is KtNameReferenceExpression && localProperties.none {\n                            // check for shadowing\n                            left.node.isGoingAfter(it.node) && it.name == left.name\n                        }\n            }\n            .mapValues { (_, left) ->\n                when (left) {\n                    is KtDotQualifiedExpression -> left.selectorExpression as KtNameReferenceExpression\n                    is KtNameReferenceExpression -> left\n                    else -> error(\"Unexpected psi class ${left::class} with text ${left.text}\")\n                }\n            }\n            .filterValues { left -> left.getReferencedName() in classProperties.mapNotNull { it.name } }\n\n    @Suppress(\n        \"NestedBlockDepth\",\n        \"GENERIC_VARIABLE_WRONG_DECLARATION\",\n        \"TOO_LONG_FUNCTION\",\n        \"TOO_MANY_PARAMETERS\",\n        \"LongParameterList\",\n    )\n    private fun ASTNode.convertSecondaryConstructorToPrimary(\n        secondaryCtor: ASTNode,\n        declarationsAssignedInCtor: List<KtProperty>,\n        nonTrivialAssignments: Map<KtBinaryExpression, KtNameReferenceExpression>,\n        otherStatements: List<KtExpression>,\n        comments: Map<String, ASTNode?>?,\n        initBody: List<String>\n    ) {\n        require(elementType == CLASS)\n\n        val localProperties = secondaryCtor.psi.collectDescendantsOfType<KtProperty> { it.isLocal }\n        // find all arguments that are not directly assigned into properties\n        val nonTrivialSecondaryCtorParameters = getNonTrivialParameters(secondaryCtor, nonTrivialAssignments.keys, localProperties)\n\n        val primaryCtorNode = createPrimaryCtor(secondaryCtor, declarationsAssignedInCtor, nonTrivialSecondaryCtorParameters)\n\n        val newArgumentListOfSecondaryCtor: List<KtParameter> = (secondaryCtor.psi as KtSecondaryConstructor)\n            .valueParameters\n            .filter { arg -> arg.name !in nonTrivialSecondaryCtorParameters.map { it.name } }  // get rid of ctor arguments\n            .filter { arg -> arg.name !in declarationsAssignedInCtor.map { it.name } }  // get rid of ctor arguments\n            .filter { arg -> initBody.any { expr -> arg.name.toString() in expr } }  // get rid of parameters that do not appear in text\n\n        if (newArgumentListOfSecondaryCtor.isNotEmpty()) {\n            return\n        }\n\n        addChild(primaryCtorNode, findChildByType(CLASS_BODY))\n        declarationsAssignedInCtor.forEach { ktProperty ->\n            ktProperty.node.run {\n                treePrev.takeIf { it.elementType == WHITE_SPACE }?.let { treeParent.removeChild(it) }\n                treeParent.removeChild(this)\n            }\n        }\n\n        // adding comments to init body\n        val initBodyWithComments = initBody.toMutableList()\n        comments?.forEach { (comment, nextExpression) ->\n            if (initBodyWithComments.indexOf(nextExpression?.text) != -1) {\n                initBodyWithComments.add(initBodyWithComments.indexOf(nextExpression?.text), comment)\n            }\n        }\n\n        if (otherStatements.isNotEmpty() || nonTrivialAssignments.isNotEmpty()) {\n            findChildByType(CLASS_BODY)?.run {\n                val classInitializer = kotlinParser.createNodeForInit(\n                    \"\"\"|init {\n                       |    ${initBodyWithComments.joinToString(\"\\n\")}\n                       |}\n                    \"\"\".trimMargin())\n                addChild(classInitializer, secondaryCtor)\n                addChild(PsiWhiteSpaceImpl(\"\\n\"), secondaryCtor)\n            }\n        }\n\n        secondaryCtor\n            .run { treePrev.takeIf { it.elementType == WHITE_SPACE } ?: treeNext }\n            .takeIf { it.elementType == WHITE_SPACE }\n            ?.run { treeParent.removeChild(this) }\n        findChildByType(CLASS_BODY)?.removeChild(secondaryCtor)\n    }\n\n    @Suppress(\"UnsafeCallOnNullableType\")\n    private fun getNonTrivialParameters(secondaryCtor: ASTNode,\n                                        nonTrivialAssignments: Collection<KtBinaryExpression>,\n                                        localProperties: List<KtProperty>\n    ) = (secondaryCtor.psi as KtSecondaryConstructor)\n        .valueParameters.run {\n            val dependencies = nonTrivialAssignments\n                .flatMap { it.left!!.collectDescendantsOfType<KtNameReferenceExpression>() }\n                .filterNot { ref ->\n                    localProperties.any { ref.node.isGoingAfter(it.node) && ref.getReferencedName() == it.name }\n                }\n                .map { it.getReferencedName() }\n            filter {\n                it.name in dependencies\n            }\n        }\n\n    private fun createPrimaryCtor(secondaryCtor: ASTNode,\n                                  declarationsAssignedInCtor: List<KtProperty>,\n                                  valueParameters: List<KtParameter>\n    ) = kotlinParser.createPrimaryConstructor(\n        (secondaryCtor\n            .findChildByType(MODIFIER_LIST)\n            ?.text\n            ?.plus(\" constructor \")\n            ?: \"\") +\n                \"(\" +\n                declarationsAssignedInCtor.run {\n                    joinToString(\n                        \", \",\n                        postfix = if (isNotEmpty() && valueParameters.isNotEmpty()) \", \" else \"\"\n                    ) { it.text }\n                } +\n                valueParameters.joinToString(\", \") { it.text } +\n                \")\"\n    )\n        .node\n\n    companion object {\n        const val NAME_ID = \"single-constructor\"\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/main/kotlin/com/saveourtool/diktat/ruleset/rules/chapter6/classes/SingleInitRule.kt",
    "content": "package com.saveourtool.diktat.ruleset.rules.chapter6.classes\n\nimport com.saveourtool.diktat.common.config.rules.RulesConfig\nimport com.saveourtool.diktat.ruleset.constants.Warnings.MULTIPLE_INIT_BLOCKS\nimport com.saveourtool.diktat.ruleset.rules.DiktatRule\nimport com.saveourtool.diktat.ruleset.utils.findAllDescendantsWithSpecificType\nimport com.saveourtool.diktat.ruleset.utils.getAllChildrenWithType\nimport com.saveourtool.diktat.ruleset.utils.getIdentifierName\nimport com.saveourtool.diktat.ruleset.utils.parent\n\nimport org.jetbrains.kotlin.KtNodeTypes\nimport org.jetbrains.kotlin.KtNodeTypes.BLOCK\nimport org.jetbrains.kotlin.KtNodeTypes.CLASS_BODY\nimport org.jetbrains.kotlin.KtNodeTypes.CLASS_INITIALIZER\nimport org.jetbrains.kotlin.KtNodeTypes.PRIMARY_CONSTRUCTOR\nimport org.jetbrains.kotlin.KtNodeTypes.PROPERTY\nimport org.jetbrains.kotlin.KtNodeTypes.REFERENCE_EXPRESSION\nimport org.jetbrains.kotlin.KtNodeTypes.VALUE_PARAMETER_LIST\nimport org.jetbrains.kotlin.com.intellij.lang.ASTNode\nimport org.jetbrains.kotlin.com.intellij.psi.impl.source.tree.LeafPsiElement\nimport org.jetbrains.kotlin.com.intellij.psi.impl.source.tree.PsiWhiteSpaceImpl\nimport org.jetbrains.kotlin.lexer.KtTokens.EQ\nimport org.jetbrains.kotlin.lexer.KtTokens.WHITE_SPACE\nimport org.jetbrains.kotlin.psi.KtBlockExpression\nimport org.jetbrains.kotlin.psi.KtNameReferenceExpression\nimport org.jetbrains.kotlin.psi.KtParameter\nimport org.jetbrains.kotlin.psi.KtProperty\nimport org.jetbrains.kotlin.psi.psiUtil.asAssignment\nimport org.jetbrains.kotlin.psi.psiUtil.children\n\n/**\n * The rule that checks whether a class has a single `init` block or multiple. Having multiple `init` blocks is a bad practice.\n */\nclass SingleInitRule(configRules: List<RulesConfig>) : DiktatRule(\n    NAME_ID,\n    configRules,\n    listOf(MULTIPLE_INIT_BLOCKS)\n) {\n    override fun logic(node: ASTNode) {\n        when (node.elementType) {\n            CLASS_BODY -> handleInitBlocks(node)\n            else -> return\n        }\n    }\n\n    private fun handleInitBlocks(node: ASTNode) {\n        // merge init blocks if there are multiple\n        node\n            .children()\n            .filter { it.elementType == CLASS_INITIALIZER }\n            .toList()\n            .takeIf { it.size > 1 }\n            ?.let { initBlocks ->\n                val className = node.treeParent.getIdentifierName()?.text\n                MULTIPLE_INIT_BLOCKS.warnAndFix(configRules, emitWarn, isFixMode,\n                    \"in class <$className> found ${initBlocks.size} `init` blocks\", node.startOffset, node) {\n                    mergeInitBlocks(initBlocks)\n                }\n            }\n\n        // move property assignments from init block to property declarations\n        node.findChildByType(CLASS_INITIALIZER)?.let { initBlock ->\n            val propertiesFromPrimaryConstructor = node\n                .treeParent\n                .findChildByType(PRIMARY_CONSTRUCTOR)\n                ?.findChildByType(VALUE_PARAMETER_LIST)\n                ?.children()\n                ?.filter { it.elementType == KtNodeTypes.VALUE_PARAMETER }\n                ?.map { it.psi as KtParameter }\n                ?.map { it.name }\n                ?.toList()\n            val propertiesFromClassBody = node\n                .children()\n                .filter { it.elementType == PROPERTY }\n                .toList()\n            moveAssignmentsToProperties(propertiesFromClassBody, propertiesFromPrimaryConstructor, initBlock)\n        }\n    }\n\n    private fun mergeInitBlocks(initBlocks: List<ASTNode>) {\n        val firstInitBlock = initBlocks.first()\n        initBlocks.drop(1).forEach { initBlock ->\n            firstInitBlock.findChildByType(BLOCK)?.run {\n                val beforeNode = lastChildNode.treePrev.takeIf { it.elementType == WHITE_SPACE } ?: lastChildNode\n                (initBlock.findChildByType(BLOCK)?.psi as? KtBlockExpression)?.statements?.forEach {\n                    addChild(PsiWhiteSpaceImpl(\"\\n\"), beforeNode)\n                    addChild(it.node.clone() as ASTNode, beforeNode)\n                }\n            }\n            if (initBlock.treePrev.elementType == WHITE_SPACE && initBlock.treeNext.elementType == WHITE_SPACE) {\n                initBlock.treeParent.removeChild(initBlock.treeNext)\n            }\n            initBlock.treeParent.removeChild(initBlock)\n        }\n        firstInitBlock.parent(CLASS_BODY)?.let(::removeEmptyBlocks)\n    }\n\n    @Suppress(\"UnsafeCallOnNullableType\", \"TOO_LONG_FUNCTION\")\n    private fun moveAssignmentsToProperties(\n        propertiesFromClassBody: List<ASTNode>,\n        propertiesFromPrimaryConstructor: List<String?>?,\n        initBlock: ASTNode\n    ) {\n        initBlock\n            .findChildByType(BLOCK)\n            ?.run {\n                (psi as KtBlockExpression)\n                    .statements\n                    .mapNotNull { it.asAssignment() }\n                    .filter { it.left is KtNameReferenceExpression }\n                    .filter { statement ->\n                        statement.right?.node?.findAllDescendantsWithSpecificType(REFERENCE_EXPRESSION)?.all { arg ->\n                            propertiesFromClassBody.any { (it.psi as KtProperty).name == arg.text } || propertiesFromPrimaryConstructor?.any { it == arg.text } == true\n                        } ?: false\n                    }\n                    .groupBy { assignment ->\n                        val assignedRef = assignment.left as KtNameReferenceExpression\n                        propertiesFromClassBody.find { (it.psi as KtProperty).name == assignedRef.getReferencedName() }\n                    }\n                    .filterKeys { it != null }\n                    .mapKeys { (k, _) -> k as ASTNode }\n                    .filter { (property, assignments) ->\n                        !(property.psi as KtProperty).hasBody() && assignments.size == 1\n                    }\n                    .takeIf { it.isNotEmpty() }\n                    ?.let { map ->\n                        MULTIPLE_INIT_BLOCKS.warnAndFix(configRules, emitWarn, isFixMode,\n                            \"`init` block has assignments that can be moved to declarations\", initBlock.startOffset, initBlock\n                        ) {\n                            map.forEach { (property, assignments) ->\n                                val assignment = assignments.single()\n                                property.addChild(PsiWhiteSpaceImpl(\" \"), null)\n                                property.addChild(LeafPsiElement(EQ, \"=\"), null)\n                                property.addChild(PsiWhiteSpaceImpl(\" \"), null)\n                                property.addChild(assignment.right!!.node.clone() as ASTNode, null)\n                                assignment.node.run {\n                                    if (treePrev.elementType == WHITE_SPACE) {\n                                        treeParent.removeChild(treePrev)\n                                    }\n                                    treeParent.removeChild(this)\n                                }\n                            }\n                        }\n                    }\n            }\n        initBlock.parent(CLASS_BODY)?.let(::removeEmptyBlocks)\n    }\n\n    private fun removeEmptyBlocks(node: ASTNode) {\n        node\n            .getAllChildrenWithType(CLASS_INITIALIZER)\n            .filter {\n                (it.findChildByType(BLOCK)?.psi as KtBlockExpression?)?.statements?.isEmpty() ?: false\n            }\n            .forEach {\n                it.treeParent.removeChild(it)\n            }\n    }\n\n    companion object {\n        const val NAME_ID = \"multiple-init-block\"\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/main/kotlin/com/saveourtool/diktat/ruleset/rules/chapter6/classes/StatelessClassesRule.kt",
    "content": "package com.saveourtool.diktat.ruleset.rules.chapter6.classes\n\nimport com.saveourtool.diktat.common.config.rules.RulesConfig\nimport com.saveourtool.diktat.ruleset.constants.Warnings.OBJECT_IS_PREFERRED\nimport com.saveourtool.diktat.ruleset.rules.DiktatRule\nimport com.saveourtool.diktat.ruleset.utils.findAllDescendantsWithSpecificType\nimport com.saveourtool.diktat.ruleset.utils.getAllChildrenWithType\nimport com.saveourtool.diktat.ruleset.utils.getFirstChildWithType\nimport com.saveourtool.diktat.ruleset.utils.hasChildOfType\n\nimport org.jetbrains.kotlin.KtNodeTypes.CLASS\nimport org.jetbrains.kotlin.KtNodeTypes.FUN\nimport org.jetbrains.kotlin.KtNodeTypes.OBJECT_DECLARATION\nimport org.jetbrains.kotlin.KtNodeTypes.SUPER_TYPE_ENTRY\nimport org.jetbrains.kotlin.KtNodeTypes.SUPER_TYPE_LIST\nimport org.jetbrains.kotlin.com.intellij.lang.ASTFactory\nimport org.jetbrains.kotlin.com.intellij.lang.ASTNode\nimport org.jetbrains.kotlin.lexer.KtTokens.CLASS_KEYWORD\nimport org.jetbrains.kotlin.lexer.KtTokens.IDENTIFIER\nimport org.jetbrains.kotlin.lexer.KtTokens.INTERFACE_KEYWORD\nimport org.jetbrains.kotlin.lexer.KtTokens.OBJECT_KEYWORD\nimport org.jetbrains.kotlin.psi.KtClass\nimport org.jetbrains.kotlin.psi.psiUtil.children\nimport org.jetbrains.kotlin.psi.stubs.elements.KtFileElementType\n\n/**\n * This rule checks if class is stateless and if so changes it to object.\n */\nclass StatelessClassesRule(configRules: List<RulesConfig>) : DiktatRule(\n    NAME_ID,\n    configRules,\n    listOf(OBJECT_IS_PREFERRED)\n) {\n    override fun logic(node: ASTNode) {\n        // Fixme: We should find interfaces in all project and then check them\n        if (node.elementType == KtFileElementType.INSTANCE) {\n            val interfacesNodes = node\n                .findAllDescendantsWithSpecificType(CLASS)\n                .filter { it.hasChildOfType(INTERFACE_KEYWORD) }\n            node\n                .findAllDescendantsWithSpecificType(CLASS)\n                .filterNot { it.hasChildOfType(INTERFACE_KEYWORD) }\n                .forEach { handleClass(it, interfacesNodes) }\n        }\n    }\n\n    @Suppress(\"UnsafeCallOnNullableType\")\n    private fun handleClass(node: ASTNode, interfaces: List<ASTNode>) {\n        if (isClassExtendsValidInterface(node, interfaces) && isStatelessClass(node)) {\n            OBJECT_IS_PREFERRED.warnAndFix(configRules, emitWarn, isFixMode,\n                \"class ${(node.psi as KtClass).name!!}\", node.startOffset, node) {\n                val newObjectNode = ASTFactory.composite(OBJECT_DECLARATION)\n                val children = node.children().toList()\n                node.treeParent.addChild(newObjectNode, node)\n                children.forEach {\n                    if (it.elementType == CLASS_KEYWORD) {\n                        newObjectNode.addChild(ASTFactory.leaf(OBJECT_KEYWORD, \"object\"))\n                    } else {\n                        newObjectNode.addChild(it)\n                    }\n                }\n                node.treeParent.removeChild(node)\n            }\n        }\n    }\n\n    private fun isStatelessClass(node: ASTNode): Boolean {\n        val properties = (node.psi as KtClass).getProperties()\n        val functions = node.findAllDescendantsWithSpecificType(FUN)\n        return properties.isEmpty() &&\n                functions.isNotEmpty() &&\n                !(node.psi as KtClass).hasExplicitPrimaryConstructor()\n    }\n\n    private fun isClassExtendsValidInterface(node: ASTNode, interfaces: List<ASTNode>): Boolean =\n        node.findChildByType(SUPER_TYPE_LIST)\n            ?.getAllChildrenWithType(SUPER_TYPE_ENTRY)\n            ?.isNotEmpty()\n            ?.and(isClassInheritsStatelessInterface(node, interfaces))\n            ?: false\n\n    @Suppress(\"UnsafeCallOnNullableType\")\n    private fun isClassInheritsStatelessInterface(node: ASTNode, interfaces: List<ASTNode>): Boolean {\n        val classInterfaces = node\n            .findChildByType(SUPER_TYPE_LIST)\n            ?.getAllChildrenWithType(SUPER_TYPE_ENTRY)\n\n        val foundInterfaces = interfaces.filter { inter ->\n            classInterfaces!!.any { it.text == inter.getFirstChildWithType(IDENTIFIER)!!.text }\n        }\n\n        return foundInterfaces.any { (it.psi as KtClass).getProperties().isEmpty() }\n    }\n\n    companion object {\n        const val NAME_ID = \"stateless-class\"\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/main/kotlin/com/saveourtool/diktat/ruleset/utils/AstConstants.kt",
    "content": "@file:Suppress(\"FILE_NAME_MATCH_CLASS\")\n\npackage com.saveourtool.diktat.ruleset.utils\n\nimport org.jetbrains.kotlin.KtNodeTypes.DO_WHILE\nimport org.jetbrains.kotlin.KtNodeTypes.FOR\nimport org.jetbrains.kotlin.KtNodeTypes.WHILE\nimport org.jetbrains.kotlin.kdoc.lexer.KDocTokens.KDOC\nimport org.jetbrains.kotlin.lexer.KtTokens.BLOCK_COMMENT\nimport org.jetbrains.kotlin.lexer.KtTokens.EOL_COMMENT\nimport org.jetbrains.kotlin.lexer.KtTokens.LBRACE\nimport org.jetbrains.kotlin.lexer.KtTokens.RBRACE\nimport org.jetbrains.kotlin.lexer.KtTokens.SEMICOLON\nimport org.jetbrains.kotlin.lexer.KtTokens.WHITE_SPACE\n\ninternal const val GET_PREFIX = \"get\"\ninternal const val SET_PREFIX = \"set\"\ninternal const val EMPTY_BLOCK_TEXT = \"{}\"\n\n/**\n * List of standard methods which do not need mandatory documentation\n */\ninternal val standardMethods = listOf(\"main\", \"equals\", \"hashCode\", \"toString\", \"clone\", \"finalize\")\n\n/**\n * Mapping (value is negative infix) of infix methods that return Boolean\n */\ninternal val logicalInfixMethodMapping = mapOf(\n    \"==\" to \"!=\",\n    \"!=\" to \"==\",\n    \">\" to \"<=\",\n    \"<\" to \">=\",\n    \">=\" to \"<\",\n    \"<=\" to \">\",\n    \"in\" to \"!in\",\n    \"!in\" to \"in\",\n)\n\n/**\n * List of infix methods that return Boolean\n */\ninternal val logicalInfixMethods = logicalInfixMethodMapping.keys + \"xor\"\n\n/**\n * List of element types present in empty code block `{ }`\n */\nval emptyBlockList = listOf(LBRACE, WHITE_SPACE, SEMICOLON, RBRACE)\n\nval commentType = listOf(BLOCK_COMMENT, EOL_COMMENT, KDOC)\nval loopType = listOf(FOR, WHILE, DO_WHILE)\nval copyrightWords = setOf(\"copyright\", \"版权\")\n\ninternal val operatorMap = mapOf(\n    \"unaryPlus\" to \"+\", \"unaryMinus\" to \"-\", \"not\" to \"!\",\n    \"plus\" to \"+\", \"minus\" to \"-\", \"times\" to \"*\", \"div\" to \"/\", \"rem\" to \"%\", \"mod\" to \"%\", \"rangeTo\" to \"..\",\n    \"inc\" to \"++\", \"dec\" to \"--\", \"contains\" to \"in\",\n    \"plusAssign\" to \"+=\", \"minusAssign\" to \"-=\", \"timesAssign\" to \"*=\", \"divAssign\" to \"/=\", \"modAssign\" to \"%=\",\n).mapValues { (_, value) ->\n    listOf(value)\n} + mapOf(\n    \"equals\" to listOf(\"==\", \"!=\"),\n    \"compareTo\" to listOf(\"<\", \"<=\", \">\", \">=\"),\n)\n\ninternal val ignoreImports = setOf(\"invoke\", \"get\", \"set\", \"getValue\", \"setValue\", \"provideDelegate\")\n\n/**\n * Enum that represents some standard platforms that can appear in kotlin code\n * @property packages beginnings of fully qualified names of packages belonging to a particular platform\n */\nenum class StandardPlatforms(val packages: List<String>) {\n    ANDROID(listOf(\"android\", \"androidx\", \"com.android\")),\n    JAVA(listOf(\"java\", \"javax\")),\n    KOTLIN(listOf(\"kotlin\", \"kotlinx\")),\n    ;\n}\n"
  },
  {
    "path": "diktat-rules/src/main/kotlin/com/saveourtool/diktat/ruleset/utils/AstNodeUtils.kt",
    "content": "/**\n * Various utility methods to work with kotlin AST\n * FixMe: fix suppressed inspections on KDocs\n */\n\n@file:Suppress(\n    \"FILE_NAME_MATCH_CLASS\",\n    \"KDOC_WITHOUT_RETURN_TAG\",\n    \"KDOC_WITHOUT_PARAM_TAG\",\n    \"MatchingDeclarationName\",\n)\n\npackage com.saveourtool.diktat.ruleset.utils\n\nimport com.saveourtool.diktat.DIKTAT\nimport com.saveourtool.diktat.api.isAnnotatedWithIgnoredAnnotation\nimport com.saveourtool.diktat.common.config.rules.Rule\nimport com.saveourtool.diktat.common.config.rules.RulesConfig\nimport com.saveourtool.diktat.ruleset.rules.chapter1.PackageNaming\n\nimport org.jetbrains.kotlin.KtNodeTypes\nimport org.jetbrains.kotlin.KtNodeTypes.ANNOTATED_EXPRESSION\nimport org.jetbrains.kotlin.KtNodeTypes.ANNOTATION_ENTRY\nimport org.jetbrains.kotlin.KtNodeTypes.BINARY_EXPRESSION\nimport org.jetbrains.kotlin.KtNodeTypes.CALL_EXPRESSION\nimport org.jetbrains.kotlin.KtNodeTypes.FILE_ANNOTATION_LIST\nimport org.jetbrains.kotlin.KtNodeTypes.FUN\nimport org.jetbrains.kotlin.KtNodeTypes.FUNCTION_LITERAL\nimport org.jetbrains.kotlin.KtNodeTypes.IMPORT_LIST\nimport org.jetbrains.kotlin.KtNodeTypes.LAMBDA_EXPRESSION\nimport org.jetbrains.kotlin.KtNodeTypes.LONG_STRING_TEMPLATE_ENTRY\nimport org.jetbrains.kotlin.KtNodeTypes.MODIFIER_LIST\nimport org.jetbrains.kotlin.KtNodeTypes.OPERATION_REFERENCE\nimport org.jetbrains.kotlin.KtNodeTypes.PARENTHESIZED\nimport org.jetbrains.kotlin.KtNodeTypes.PROPERTY\nimport org.jetbrains.kotlin.KtNodeTypes.REFERENCE_EXPRESSION\nimport org.jetbrains.kotlin.KtNodeTypes.TYPE_PARAMETER_LIST\nimport org.jetbrains.kotlin.KtNodeTypes.TYPE_REFERENCE\nimport org.jetbrains.kotlin.KtNodeTypes.VALUE_PARAMETER_LIST\nimport org.jetbrains.kotlin.builtins.PrimitiveType\nimport org.jetbrains.kotlin.com.intellij.lang.ASTNode\nimport org.jetbrains.kotlin.com.intellij.openapi.util.Key\nimport org.jetbrains.kotlin.com.intellij.psi.PsiElement\nimport org.jetbrains.kotlin.com.intellij.psi.TokenType\nimport org.jetbrains.kotlin.com.intellij.psi.impl.source.tree.LeafPsiElement\nimport org.jetbrains.kotlin.com.intellij.psi.impl.source.tree.PsiWhiteSpaceImpl\nimport org.jetbrains.kotlin.com.intellij.psi.tree.IElementType\nimport org.jetbrains.kotlin.com.intellij.psi.tree.TokenSet\nimport org.jetbrains.kotlin.js.translate.declaration.hasCustomGetter\nimport org.jetbrains.kotlin.js.translate.declaration.hasCustomSetter\nimport org.jetbrains.kotlin.kdoc.lexer.KDocTokens.KDOC\nimport org.jetbrains.kotlin.lexer.KtTokens\nimport org.jetbrains.kotlin.lexer.KtTokens.ANDAND\nimport org.jetbrains.kotlin.lexer.KtTokens.BLOCK_COMMENT\nimport org.jetbrains.kotlin.lexer.KtTokens.CONST_KEYWORD\nimport org.jetbrains.kotlin.lexer.KtTokens.DOT\nimport org.jetbrains.kotlin.lexer.KtTokens.ELVIS\nimport org.jetbrains.kotlin.lexer.KtTokens.EOL_COMMENT\nimport org.jetbrains.kotlin.lexer.KtTokens.EQ\nimport org.jetbrains.kotlin.lexer.KtTokens.IDENTIFIER\nimport org.jetbrains.kotlin.lexer.KtTokens.INTERNAL_KEYWORD\nimport org.jetbrains.kotlin.lexer.KtTokens.LATEINIT_KEYWORD\nimport org.jetbrains.kotlin.lexer.KtTokens.LBRACE\nimport org.jetbrains.kotlin.lexer.KtTokens.OROR\nimport org.jetbrains.kotlin.lexer.KtTokens.OVERRIDE_KEYWORD\nimport org.jetbrains.kotlin.lexer.KtTokens.PRIVATE_KEYWORD\nimport org.jetbrains.kotlin.lexer.KtTokens.PROTECTED_KEYWORD\nimport org.jetbrains.kotlin.lexer.KtTokens.PUBLIC_KEYWORD\nimport org.jetbrains.kotlin.lexer.KtTokens.SAFE_ACCESS\nimport org.jetbrains.kotlin.lexer.KtTokens.WHITE_SPACE\nimport org.jetbrains.kotlin.psi.KtAnnotationEntry\nimport org.jetbrains.kotlin.psi.KtClass\nimport org.jetbrains.kotlin.psi.KtFile\nimport org.jetbrains.kotlin.psi.KtIfExpression\nimport org.jetbrains.kotlin.psi.KtNullableType\nimport org.jetbrains.kotlin.psi.KtParameterList\nimport org.jetbrains.kotlin.psi.KtProperty\nimport org.jetbrains.kotlin.psi.KtTypeReference\nimport org.jetbrains.kotlin.psi.KtUserType\nimport org.jetbrains.kotlin.psi.psiUtil.children\nimport org.jetbrains.kotlin.psi.psiUtil.getChildOfType\nimport org.jetbrains.kotlin.psi.psiUtil.getChildrenOfType\nimport org.jetbrains.kotlin.psi.psiUtil.isPrivate\nimport org.jetbrains.kotlin.psi.psiUtil.parents\nimport org.jetbrains.kotlin.psi.psiUtil.siblings\nimport org.jetbrains.kotlin.psi.stubs.elements.KtFileElementType\n\nimport java.util.Locale\n\n/**\n * AST node visitor which accepts the node and, optionally, returns a value.\n */\ntypealias AstNodeVisitor<T> = (node: ASTNode) -> T\n\n/**\n * The predicate which accepts a node and returns a `boolean` value.\n */\ntypealias AstNodePredicate = AstNodeVisitor<Boolean>\n\n/**\n * A class that represents result of nodes swapping. [oldNodes] should always have same size as [newNodes]\n *\n * @property oldNodes nodes that were to be moved\n * @property newNodes nodes that have been moved\n */\ndata class ReplacementResult(val oldNodes: List<ASTNode>, val newNodes: List<ASTNode>) {\n    init {\n        require(oldNodes.size == newNodes.size)\n    }\n}\n\n/**\n * @return the highest parent node of the tree\n */\nfun ASTNode.getRootNode() = if (isRoot()) this else parents().last()\n\n/**\n * Checks whether [this] node's text has length in range [range]\n *\n * @param range an [IntRange] for text\n * @return boolean result\n */\nfun ASTNode.isTextLengthInRange(range: IntRange): Boolean = this.textLength in range\n\n/**\n * getting first child name with IDENTIFIER type\n *\n * @return node with type [org.jetbrains.kotlin.KtNodeTypes.IDENTIFIER] or null if it is not present\n */\nfun ASTNode.getIdentifierName(): ASTNode? =\n    this.getFirstChildWithType(IDENTIFIER)\n\n/**\n * getting first child name with TYPE_PARAMETER_LIST type\n *\n * @return a node with type TYPE_PARAMETER_LIST or null if it is not present\n */\nfun ASTNode.getTypeParameterList(): ASTNode? =\n    this.getFirstChildWithType(TYPE_PARAMETER_LIST)\n\n/**\n * @return true if this node contains no error elements, false otherwise\n */\nfun ASTNode.isCorrect() = this.findAllDescendantsWithSpecificType(TokenType.ERROR_ELEMENT).isEmpty()\n\n/**\n * obviously returns list with children that match particular element type\n *\n * @param elementType the [IElementType] to search\n * @return list of nodes\n */\nfun ASTNode.getAllChildrenWithType(elementType: IElementType): List<ASTNode> =\n    this.getChildren(null).filter { it.elementType == elementType }\n\n/**\n * Generates a sequence of this ASTNode's children in reversed order\n *\n * @return a reversed sequence of children\n */\nfun ASTNode.reversedChildren(): Sequence<ASTNode> = sequence {\n    var node = lastChildNode\n    while (node != null) {\n        yield(node)\n        node = node.treePrev\n    }\n}\n\n/**\n * Replaces `this` node's child [beforeNode] of type [WHITE_SPACE] with the node with specified [text]\n *\n * @param beforeNode a node to replace\n * @param text a text (white space characters only) for the new node\n */\nfun ASTNode.replaceWhiteSpaceText(beforeNode: ASTNode, text: String) {\n    require(beforeNode.elementType == WHITE_SPACE)\n    this.addChild(PsiWhiteSpaceImpl(text), beforeNode)\n    this.removeChild(beforeNode)\n}\n\n/**\n * obviously returns first child that match particular element type\n *\n * @param elementType an [IElementType\n * @return a node or null if it was not found\n */\nfun ASTNode.getFirstChildWithType(elementType: IElementType): ASTNode? =\n    this.findChildByType(elementType)\n\n/**\n * Checks if a function is anonymous\n * throws exception if the node type is different from FUN\n */\nfun ASTNode.isAnonymousFunction(): Boolean {\n    require(this.elementType == FUN)\n    return this.getIdentifierName() == null\n}\n\n/**\n * Checks if the function has boolean return type\n *\n * @return true if the function has boolean return type\n */\nfun ASTNode.hasBooleanReturnType(): Boolean {\n    val functionReturnType = this.findChildAfter(VALUE_PARAMETER_LIST, KtNodeTypes.TYPE_REFERENCE)?.text\n    return functionReturnType != null && functionReturnType == PrimitiveType.BOOLEAN.typeName.asString()\n}\n\n/**\n * Checks if the function is an operator function\n *\n * @return true if the function is an operator function\n */\nfun ASTNode.isOperatorFun(): Boolean {\n    val modifierListNode = this.findChildByType(MODIFIER_LIST)\n    return modifierListNode?.hasChildMatching { it.elementType == KtTokens.OPERATOR_KEYWORD } ?: false\n}\n\n/**\n * Checks if the symbols in this node are at the end of line\n */\nfun ASTNode.isEol() = parent(false) { it.treeNext != null }?.isFollowedByNewline() ?: true\n\n/**\n * Checks if there is a newline after symbol corresponding to this element. We can't always check only this node itself, because\n * some nodes are placed not on the same level as white spaces, e.g. operators like [ElementType.ANDAND] are children of [ElementType.OPERATION_REFERENCE].\n * Same is true also for semicolons in some cases.\n * Therefore, to check if they are followed by newline we need to check their parents.\n */\n@Suppress(\"PARAMETER_NAME_IN_OUTER_LAMBDA\")\nfun ASTNode.isFollowedByNewline() =\n    parent(false) { it.treeNext != null }?.let {\n        val probablyWhitespace = it.treeNext\n        it.isFollowedByNewlineCheck() ||\n                (probablyWhitespace.elementType == WHITE_SPACE && probablyWhitespace.treeNext.run {\n                    elementType == EOL_COMMENT && isFollowedByNewlineCheck()\n                })\n    } ?: false\n\n/**\n * This function is similar to isFollowedByNewline(), but there may be a comment after the node\n */\nfun ASTNode.isFollowedByNewlineWithComment() =\n    parent(false) { it.treeNext != null }\n        ?.treeNext?.run {\n        when (elementType) {\n            WHITE_SPACE -> text.contains(\"\\n\")\n            EOL_COMMENT, BLOCK_COMMENT, KDOC -> isFollowedByNewline()\n            else -> false\n        } ||\n                parent(false) { it.treeNext != null }?.let {\n                    it.treeNext.elementType == EOL_COMMENT && it.treeNext.isFollowedByNewline()\n                } ?: false\n    } ?: false\n\n/**\n * Checks if there is a newline before this element. See [isFollowedByNewline] for motivation on parents check.\n * Or if there is nothing before, it cheks, that there are empty imports and package before (Every FILE node has children of type IMPORT_LIST and PACKAGE)\n */\nfun ASTNode.isBeginByNewline() =\n    parent(false) { it.treePrev != null }?.let {\n        it.treePrev.elementType == WHITE_SPACE && it.treePrev.text.contains(\"\\n\") ||\n                (it.treePrev.elementType == IMPORT_LIST && it.treePrev.isLeaf() && it.treePrev.treePrev.isLeaf())\n    } ?: false\n\n/**\n * Checks if there is a newline before this element or before comment before. See [isBeginByNewline] for motivation on parents check.\n */\nfun ASTNode.isBeginNewLineWithComment() =\n    isBeginByNewline() || siblings(forward = false).takeWhile { !it.textContains('\\n') }.toList().run {\n        all { it.isWhiteSpace() || it.isPartOfComment() } && isNotEmpty()\n    }\n\n/**\n * checks if the node has corresponding child with elementTyp\n */\nfun ASTNode.hasChildOfType(elementType: IElementType) =\n    this.getFirstChildWithType(elementType) != null\n\n/**\n * Checks whether the node has at least one child of at least one of [elementType]\n *\n * @param elementType vararg of [IElementType]\n */\nfun ASTNode.hasAnyChildOfTypes(vararg elementType: IElementType) =\n    elementType.any { this.hasChildOfType(it) }\n\n/**\n * checks if node has parent of type\n */\nfun ASTNode.hasParent(type: IElementType) = parent(type) != null\n\n/**\n * check if node's text is empty (contains only left and right braces)\n * check text because some nodes have empty BLOCK element inside (lambda)\n */\nfun ASTNode?.isBlockEmpty() = this?.let {\n    if (this.elementType == KtNodeTypes.WHEN) {\n        val firstIndex = this.text.indexOf(\"{\")\n        this.text.substring(firstIndex - 1).replace(\"\\\\s+\".toRegex(), \"\") == EMPTY_BLOCK_TEXT\n    } else {\n        this.text.replace(\"\\\\s+\".toRegex(), \"\") == EMPTY_BLOCK_TEXT\n    }\n} ?: true\n\n/**\n * Method that is trying to find and return child of this node, which\n * 1) stands before the node with type @beforeThisNodeType\n * 2) has type @childNodeType\n * 2) is closest to node with @beforeThisNodeType (i.e. is first in reversed list of children, starting at @beforeThisNodeType)\n */\nfun ASTNode.findChildBefore(beforeThisNodeType: IElementType, childNodeType: IElementType): ASTNode? {\n    val anchorNode = getChildren(null)\n        .find { it.elementType == beforeThisNodeType }\n    getChildren(null)\n        .toList()\n        .let { children ->\n            anchorNode?.run {\n                children.subList(0, children.indexOf(anchorNode))\n            }\n                ?: children\n        }\n        .reversed()\n        .find { it.elementType == childNodeType }\n        ?.let { return it }\n\n    return null\n}\n\n/**\n * method that is trying to find and return FIRST node that matches these conditions:\n * 1) it is one of children of \"this\"\n * 2) it stands in the list of children AFTER the node with type @afterThisNodeType\n * 3) it has type @childNodeType\n */\nfun ASTNode.findChildAfter(afterThisNodeType: IElementType, childNodeType: IElementType): ASTNode? {\n    var foundAnchorNode = false\n    getChildren(null).forEach {\n        if (foundAnchorNode && it.elementType == childNodeType) {\n            // if we have already found previous node and type matches - then can return child\n            return it\n        }\n        if (it.elementType == afterThisNodeType) {\n            // found the node that is used as anchor and we are trying to find\n            // a node with IElementType that stands after this anchor node\n            foundAnchorNode = true\n        }\n    }\n\n    return null\n}\n\n/**\n * method that traverses previous nodes until it finds needed node or it finds stop node\n *\n * @return ASTNode?\n */\nfun ASTNode.prevNodeUntilNode(stopNodeType: IElementType, checkNodeType: IElementType): ASTNode? =\n    siblings(false).takeWhile { it.elementType != stopNodeType }.find { it.elementType == checkNodeType }\n\n/**\n * Returns all siblings of [this] node\n *\n * @param withSelf whether [this] node is included in the result\n * @return list of siblings\n */\nfun ASTNode.allSiblings(withSelf: Boolean = false): List<ASTNode> =\n    siblings(false).toList() + (if (withSelf) listOf(this) else emptyList()) + siblings(true)\n\n/**\n * Checks whether [this] node belongs to a companion object\n *\n * @return boolean result\n */\nfun ASTNode.isNodeFromCompanionObject(): Boolean {\n    val parent = this.treeParent\n    parent?.let {\n        val grandParent = parent.treeParent\n        if (grandParent != null && grandParent.elementType == KtNodeTypes.OBJECT_DECLARATION) {\n            grandParent.findLeafWithSpecificType(KtTokens.COMPANION_KEYWORD)\n                ?.run {\n                    return true\n                }\n        }\n    }\n    return false\n}\n\n/**\n * Checks whether this node is a constant\n *\n * @return boolean result\n */\nfun ASTNode.isConstant() = (this.isNodeFromFileLevel() || this.isNodeFromObject()) && this.isValProperty() && this.isConst()\n\n/**\n * Checks whether this node is an object\n *\n * @return boolean result\n */\nfun ASTNode.isNodeFromObject(): Boolean {\n    val parent = this.treeParent\n    if (parent != null && parent.elementType == KtNodeTypes.CLASS_BODY) {\n        val grandParent = parent.treeParent\n        if (grandParent != null && grandParent.elementType == KtNodeTypes.OBJECT_DECLARATION) {\n            return true\n        }\n    }\n    return false\n}\n\n/**\n * Checks whether this node is declared on a file level\n *\n * @return boolean result\n */\nfun ASTNode.isNodeFromFileLevel(): Boolean = this.treeParent.elementType == KtFileElementType.INSTANCE\n\n/**\n * Checks whether [this] node of type PROPERTY is `val`\n */\nfun ASTNode.isValProperty() =\n    this.getChildren(null)\n        .any { it.elementType == KtTokens.VAL_KEYWORD }\n\n/**\n * Checks whether this node of type PROPERTY has `const` modifier\n */\nfun ASTNode.isConst() = this.findLeafWithSpecificType(CONST_KEYWORD) != null\n\n/**\n * Checks whether this node of type PROPERTY has `lateinit` modifier\n */\nfun ASTNode.isLateInit() = this.findLeafWithSpecificType(LATEINIT_KEYWORD) != null\n\n/**\n * @param modifier modifier to find in node\n */\nfun ASTNode.hasModifier(modifier: IElementType) = this.findChildByType(MODIFIER_LIST)?.hasChildOfType(modifier) ?: false\n\n/**\n * Checks whether [this] node of type PROPERTY is `var`\n */\nfun ASTNode.isVarProperty() =\n    this.getChildren(null)\n        .any { it.elementType == KtTokens.VAR_KEYWORD }\n\n/**\n * Replaces text of [this] node with lowercase text\n */\nfun ASTNode.toLower() {\n    (this as LeafPsiElement).rawReplaceWithText(this.text.lowercase(Locale.getDefault()))\n}\n\n/**\n * This util method does tree traversal and stores to the result all tree leaf node of particular type (elementType).\n * Recursively will visit each and every node and will get leaves of specific type. Those nodes will be added to the result.\n */\nfun ASTNode.getAllLeafsWithSpecificType(elementType: IElementType, result: MutableList<ASTNode>) {\n    // if statements here have the only right order - don't change it\n    if (this.isLeaf()) {\n        if (this.elementType == elementType) {\n            result.add(this)\n        }\n    } else {\n        this.getChildren(null).forEach {\n            it.getAllLeafsWithSpecificType(elementType, result)\n        }\n    }\n}\n\n/**\n * This util method does tree traversal and returns first node that matches specific type\n * This node isn't necessarily a leaf though method name implies it\n */\nfun ASTNode.findLeafWithSpecificType(elementType: IElementType): ASTNode? {\n    if (this.elementType == elementType) {\n        return this\n    }\n    if (this.isLeaf()) {\n        return null\n    }\n\n    return getChildren(null)\n        .mapNotNull {\n            it.findLeafWithSpecificType(elementType)\n        }\n        .firstOrNull()\n}\n\n/**\n * This method counts number of \\n in node's text\n */\nfun ASTNode.numNewLines() = text.count { it == '\\n' }\n\n/**\n * This method performs tree traversal and returns all nodes with specific element type\n */\nfun ASTNode.findAllDescendantsWithSpecificType(elementType: IElementType, withSelf: Boolean = true) =\n    findAllNodesWithCondition(withSelf) { it.elementType == elementType }\n\n/**\n * This method performs tree traversal and returns all nodes which satisfy the condition\n */\nfun ASTNode.findAllNodesWithCondition(withSelf: Boolean = true,\n                                      excludeChildrenCondition: AstNodePredicate = { false },\n                                      condition: AstNodePredicate,\n): List<ASTNode> {\n    val result = if (condition(this) && withSelf) mutableListOf(this) else mutableListOf()\n    return result + this.getChildren(null)\n        .filterNot { excludeChildrenCondition(it) }\n        .flatMap { it.findAllNodesWithCondition(withSelf = true, excludeChildrenCondition, condition) }\n}\n\n/**\n * Check a node of type CLASS if it is an enum class\n */\nfun ASTNode.isClassEnum(): Boolean = (psi as? KtClass)?.isEnum() ?: false\n\n/**\n * This method finds first parent node from the sequence of parents that has specified elementType\n */\nfun ASTNode.findParentNodeWithSpecificType(elementType: IElementType) =\n    this.parents().find { it.elementType == elementType }\n\n/**\n * Finds all children of optional type which match the predicate\n */\nfun ASTNode.findChildrenMatching(elementType: IElementType? = null,\n                                 predicate: (ASTNode) -> Boolean): List<ASTNode> =\n    getChildren(elementType?.let { TokenSet.create(it) })\n        .filter(predicate)\n\n/**\n * Check if this node has any children of optional type matching the predicate\n */\nfun ASTNode.hasChildMatching(elementType: IElementType? = null,\n                             predicate: AstNodePredicate): Boolean =\n    findChildrenMatching(elementType, predicate).isNotEmpty()\n\n/**\n * Converts this AST node and all its children to pretty string representation\n */\n@Suppress(\"AVOID_NESTED_FUNCTIONS\")\nfun ASTNode.prettyPrint(level: Int = 0, maxLevel: Int = -1): String {\n    /**\n     * AST operates with \\n only, so we need to build the whole string representation and then change line separator\n     */\n    fun ASTNode.doPrettyPrint(level: Int, maxLevel: Int): String {\n        val result = StringBuilder(\"${this.elementType}: \\\"${this.text}\\\"\").append('\\n')\n        if (maxLevel != 0) {\n            this.getChildren(null).forEach { child ->\n                result.append(\n                    \"${\"-\".repeat(level + 1)} \" +\n                            child.doPrettyPrint(level + 1, maxLevel - 1)\n                )\n            }\n        }\n        return result.toString()\n    }\n    return doPrettyPrint(level, maxLevel).replace(\"\\n\", System.lineSeparator())\n}\n\n/**\n * Checks if this modifier list corresponds to accessible outside entity.\n * The receiver should be an ASTNode with ElementType.MODIFIER_LIST, can be null if entity has no modifier list\n */\nfun ASTNode?.isAccessibleOutside(): Boolean =\n    this?.run {\n        require(this.elementType == MODIFIER_LIST)\n        this.hasAnyChildOfTypes(PUBLIC_KEYWORD, PROTECTED_KEYWORD, INTERNAL_KEYWORD) ||\n                !this.hasAnyChildOfTypes(PUBLIC_KEYWORD, INTERNAL_KEYWORD, PROTECTED_KEYWORD, PRIVATE_KEYWORD)\n    }\n        ?: true\n\n/**\n * Checks whether [this] node has a parent annotated with `@Suppress` with [warningName]\n *\n * @param warningName a name of the warning which is checked\n * @return boolean result\n */\nfun ASTNode.isSuppressed(\n    warningName: String,\n    rule: Rule,\n    configs: List<RulesConfig>\n) =\n    this.parent(false, hasAnySuppressorForInspection(warningName, rule, configs)) != null\n\n/**\n * Checks node has `override` modifier\n */\nfun ASTNode.isOverridden(): Boolean =\n    findChildByType(MODIFIER_LIST)?.findChildByType(OVERRIDE_KEYWORD) != null\n\n/**\n * removing all newlines in WHITE_SPACE node and replacing it to a one newline saving the initial indenting format\n */\nfun ASTNode.leaveOnlyOneNewLine() = leaveExactlyNumNewLines(1)\n\n/**\n * removing all newlines in WHITE_SPACE node and replacing it to [num] newlines saving the initial indenting format\n */\nfun ASTNode.leaveExactlyNumNewLines(num: Int) {\n    require(this.elementType == WHITE_SPACE)\n    (this as LeafPsiElement).rawReplaceWithText(\"${\"\\n\".repeat(num)}${this.text.replace(\"\\n\", \"\")}\")\n}\n\n/**\n * If [whiteSpaceNode] is not null and has type [WHITE_SPACE] and this [WHITE_SPACE] contains 1 line, prepend a line break to it's text.\n * If [whiteSpaceNode] is null or has`t type [WHITE_SPACE], insert a new node with a line break before [beforeNode]\n *\n * @param whiteSpaceNode a node that can possibly be modified\n * @param beforeNode a node before which a new WHITE_SPACE node will be inserted\n */\nfun ASTNode.appendNewlineMergingWhiteSpace(whiteSpaceNode: ASTNode?, beforeNode: ASTNode?) {\n    if (whiteSpaceNode != null && whiteSpaceNode.elementType == WHITE_SPACE) {\n        if (whiteSpaceNode.text.lines().size == 1) {\n            (whiteSpaceNode as LeafPsiElement).rawReplaceWithText(\"\\n${whiteSpaceNode.text}\")\n        }\n    } else {\n        addChild(PsiWhiteSpaceImpl(\"\\n\"), beforeNode)\n    }\n}\n\n/**\n * Appends newline after this node\n */\nfun ASTNode.appendNewline() {\n    val nextNode = this.treeNext\n    if (nextNode.elementType == WHITE_SPACE) {\n        (nextNode as LeafPsiElement).rawReplaceWithText(\"\\n${nextNode.text}\")\n    } else {\n        this.treeParent.addChild(PsiWhiteSpaceImpl(\"\\n\"), nextNode)\n    }\n}\n\n/**\n * Changes any whitespace node on newline node\n *\n * @param whiteSpaceNode\n * @param beforeNode\n */\nfun ASTNode.changeWhiteSpaceOnNewline(whiteSpaceNode: ASTNode?, beforeNode: ASTNode?) {\n    if (whiteSpaceNode != null && whiteSpaceNode.elementType == WHITE_SPACE) {\n        if (whiteSpaceNode.text.lines().size == 1) {\n            (whiteSpaceNode as LeafPsiElement).rawReplaceWithText(\"\\n\")\n        }\n    } else {\n        addChild(PsiWhiteSpaceImpl(\"\\n\"), beforeNode)\n    }\n}\n\n/**\n * Transforms last line of this WHITE_SPACE to exactly [indent] spaces\n */\nfun ASTNode.indentBy(indent: Int) {\n    require(this.elementType == WHITE_SPACE)\n    (this as LeafPsiElement).rawReplaceWithText(text.substringBeforeLast('\\n') + \"\\n\" + \" \".repeat(indent))\n}\n\n/**\n * @param beforeThisNode node before which childToMove will be placed. If null, childToMove will be appended after last child of this node.\n * @param withNextNode whether next node after childToMove should be moved too. In most cases it corresponds to moving\n *     the node with newline.\n */\nfun ASTNode.moveChildBefore(\n    childToMove: ASTNode,\n    beforeThisNode: ASTNode?,\n    withNextNode: Boolean = false\n): ReplacementResult {\n    require(childToMove in children()) { \"can only move child ($childToMove) of this node $this\" }\n    require(beforeThisNode == null || beforeThisNode in children()) { \"can only place node before another child ($beforeThisNode) of this node $this\" }\n    val movedChild = childToMove.clone() as ASTNode\n    val nextMovedChild = childToMove.treeNext?.takeIf { withNextNode }?.let { it.clone() as ASTNode }\n    val nextOldChild = childToMove.treeNext.takeIf { withNextNode && it != null }\n    addChild(movedChild, beforeThisNode)\n    if (nextMovedChild != null && nextOldChild != null) {\n        addChild(nextMovedChild, beforeThisNode)\n        removeChild(nextOldChild)\n    }\n    removeChild(childToMove)\n    return ReplacementResult(listOfNotNull(childToMove, nextOldChild), listOfNotNull(movedChild, nextMovedChild))\n}\n\n/**\n * Finds a first `{` node inside [this] node\n *\n * @return a LBRACE node or `null` if it can't be found\n */\n@Suppress(\"UnsafeCallOnNullableType\", \"FUNCTION_NAME_INCORRECT_CASE\", \"WRONG_NEWLINES\")\nfun ASTNode.findLBrace(): ASTNode? = when (this.elementType) {\n    KtNodeTypes.THEN, KtNodeTypes.ELSE, KtNodeTypes.FUN, KtNodeTypes.TRY, KtNodeTypes.CATCH, KtNodeTypes.FINALLY ->\n        this.findChildByType(KtNodeTypes.BLOCK)?.findChildByType(LBRACE)\n    KtNodeTypes.WHEN -> this.findChildByType(LBRACE)!!\n    in loopType ->\n        this.findChildByType(KtNodeTypes.BODY)\n            ?.findChildByType(KtNodeTypes.BLOCK)\n            ?.findChildByType(LBRACE)\n    KtNodeTypes.CLASS, KtNodeTypes.OBJECT_DECLARATION -> this.findChildByType(KtNodeTypes.CLASS_BODY)\n        ?.findChildByType(LBRACE)\n    KtNodeTypes.FUNCTION_LITERAL -> this.findChildByType(LBRACE)\n    else -> null\n}\n\n/**\n * Checks whether this node of type IF is a single line expression with single else, like `if (true) x else y`\n *\n * @return boolean result\n */\nfun ASTNode.isSingleLineIfElse(): Boolean {\n    val elseNode = (psi as KtIfExpression).`else`?.node\n    val hasSingleElse = elseNode != null && elseNode.elementType != KtNodeTypes.IF\n    return treeParent.elementType != KtNodeTypes.ELSE && hasSingleElse && text.lines().size == 1\n}\n\n/**\n * Checks whether [child] is after [afterChild] among the children of [this] node\n *\n * @return boolean result\n */\nfun ASTNode.isChildAfterAnother(child: ASTNode, afterChild: ASTNode): Boolean =\n    getChildren(null).indexOf(child) > getChildren(null).indexOf(afterChild)\n\n/**\n * Checks whether [child] is after all nodes from [group] among the children of [this] node\n *\n * @return boolean result\n */\nfun ASTNode.isChildAfterGroup(child: ASTNode, group: List<ASTNode>): Boolean =\n    getChildren(null).indexOf(child) > (group.map { getChildren(null).indexOf(it) }.maxOrNull() ?: 0)\n\n/**\n * Checks whether [child] is before [beforeChild] among the children of [this] node\n *\n * @return boolean result\n */\nfun ASTNode.isChildBeforeAnother(child: ASTNode, beforeChild: ASTNode): Boolean =\n    areChildrenBeforeGroup(listOf(child), listOf(beforeChild))\n\n/**\n * Checks whether [child] is before all nodes is [group] among the children of [this] node\n *\n * @return boolean result\n */\nfun ASTNode.isChildBeforeGroup(child: ASTNode, group: List<ASTNode>): Boolean =\n    areChildrenBeforeGroup(listOf(child), group)\n\n/**\n * Checks whether all nodes in [children] is before [beforeChild] among the children of [this] node\n *\n * @return boolean result\n */\nfun ASTNode.areChildrenBeforeChild(children: List<ASTNode>, beforeChild: ASTNode): Boolean =\n    areChildrenBeforeGroup(children, listOf(beforeChild))\n\n/**\n * Checks whether all nodes in [children] is before all nodes in [group] among the children of [this] node\n *\n * @return boolean result\n */\n@Suppress(\"UnsafeCallOnNullableType\")\nfun ASTNode.areChildrenBeforeGroup(children: List<ASTNode>, group: List<ASTNode>): Boolean {\n    require(children.isNotEmpty() && group.isNotEmpty()) { \"no sense to operate on empty lists\" }\n    return children.maxOf { getChildren(null).indexOf(it) } < group.minOf { getChildren(null).indexOf(it) }\n}\n\n/**\n * A function that rearranges nodes in a [this] list.\n *\n * @param getSiblingBlocks a function which returns nodes that should be before and after the current node\n * @param incorrectPositionHandler function that moves the current node with respect to node before which in should be placed\n */\n@Suppress(\"TYPE_ALIAS\")\nfun List<ASTNode>.handleIncorrectOrder(\n    getSiblingBlocks: ASTNode.() -> Pair<ASTNode?, ASTNode>,\n    incorrectPositionHandler: (nodeToMove: ASTNode, beforeThisNode: ASTNode) -> Unit\n) {\n    forEach { astNode ->\n        val (afterThisNode, beforeThisNode) = astNode.getSiblingBlocks()\n        val isPositionIncorrect =\n            (afterThisNode != null && !astNode.treeParent.isChildAfterAnother(astNode, afterThisNode)) ||\n                    !astNode.treeParent.isChildBeforeAnother(astNode, beforeThisNode)\n\n        if (isPositionIncorrect) {\n            incorrectPositionHandler(astNode, beforeThisNode)\n        }\n    }\n}\n\n/**\n * This method returns text of this [ASTNode] plus text from it's siblings after last and until next newline, if present in siblings.\n * I.e., if this node occupies no more than a single line, this whole line or it's part will be returned.\n */\n@Suppress(\"WRONG_NEWLINES\")\nfun ASTNode.extractLineOfText(): String {\n    val text: MutableList<String> = mutableListOf()\n    siblings(false)\n        .map { it.text.split(\"\\n\") }\n        .takeWhileInclusive { it.size <= 1 }\n        .forEach { text.add(0, it.last()) }\n    text.add(this.text)\n    val nextNode = parent(false) { it.treeNext != null } ?: this\n    nextNode.siblings(true)\n        .map { it.text.split(\"\\n\") }\n        .takeWhileInclusive { it.size <= 1 }\n        .forEach { text.add(it.first()) }\n    return text.joinToString(separator = \"\").trim()\n}\n\n/**\n * Checks node has `@Test` annotation\n */\nfun ASTNode.hasTestAnnotation() = findChildByType(MODIFIER_LIST)\n    ?.getAllChildrenWithType(ANNOTATION_ENTRY)\n    ?.flatMap { it.findAllDescendantsWithSpecificType(KtNodeTypes.CONSTRUCTOR_CALLEE) }\n    ?.any { it.findLeafWithSpecificType(KtTokens.IDENTIFIER)?.text == \"Test\" }\n    ?: false\n\n/**\n * Return the number in the file of the last line of this node's text\n */\nfun ASTNode.lastLineNumber() = getLineNumber() + text.count { it == '\\n' }\n\n/**\n * copy-pasted method from ktlint to determine line and column number by offset\n */\nfun ASTNode.calculateLineColByOffset() = buildPositionInTextLocator(text)\n\n/**\n * Return all nodes located at the specific line\n *\n * @param line\n * @return corresponding list of nodes\n */\nfun ASTNode.findAllNodesOnLine(\n    line: Int\n): List<ASTNode>? {\n    val rootNode = this.getRootNode()\n    val fileLines = rootNode.text.lines()\n\n    if (line <= 0 || line > fileLines.size) {\n        return null\n    }\n\n    val positionByOffset = rootNode.calculateLineColByOffset()\n\n    val lineOffset = this.findOffsetByLine(line, positionByOffset)\n\n    return this.getAllNodesOnLine(lineOffset, line, positionByOffset).toList()\n}\n\n/**\n * Return all nodes located at the specific line satisfying [condition]\n *\n * @param line\n * @param condition\n * @return corresponding list of nodes\n */\nfun ASTNode.findAllNodesWithConditionOnLine(\n    line: Int,\n    condition: AstNodePredicate\n): List<ASTNode>? = this.findAllNodesOnLine(line)?.filter(condition)\n\n/**\n * Safely retrieves file name from user data of this node\n *\n * @return name of the file [this] node belongs to or null\n */\nfun ASTNode.getFilePathSafely(): String? = run {\n    val rootNode = getRootNode()\n\n    @Suppress(\"DEPRECATION\")\n    Key.findKeyByName(\"FILE_PATH\")\n        ?.let { key ->\n            rootNode.getUserData(key)\n                ?.let { it as? String }\n        }\n        ?: run {\n            // KtLint doesn't set file path for snippets\n            // will take a file name from KtFile\n            // it doesn't work for all cases since KtLint creates KtFile using a file name, not a file path\n            // https://github.com/pinterest/ktlint/issues/1921\n            (rootNode.psi as? KtFile)?.virtualFilePath\n        }\n}\n\n/**\n * Retrieves file name from user data of this node\n *\n * @return name of the file [this] node belongs to\n */\nfun ASTNode.getFilePath(): String = requireNotNull(getFilePathSafely()) {\n    \"Failed to retrieve a file path for node $this (${this.javaClass.simpleName})\"\n}\n\n/**\n * checks that this one node is placed after the other node in code (by comparing lines of code where nodes start)\n */\nfun ASTNode.isGoingAfter(otherNode: ASTNode): Boolean {\n    val thisLineNumber = this.getLineNumber()\n    val otherLineNumber = otherNode.getLineNumber()\n\n    return (thisLineNumber > otherLineNumber)\n}\n\n/**\n * check that node has binary expression with `EQ`\n */\nfun ASTNode.hasEqBinaryExpression(): Boolean =\n    findChildByType(BINARY_EXPRESSION)\n        ?.findChildByType(OPERATION_REFERENCE)\n        ?.hasChildOfType(EQ)\n        ?: false\n\n/**\n * Get line number, where this node's content starts.\n *\n * @return line number\n */\nfun ASTNode.getLineNumber(): Int =\n    calculateLineNumber()\n\n/**\n * Get node by taking children by types and ignore `PARENTHESIZED`\n *\n * @return child of type\n */\nfun ASTNode.takeByChainOfTypes(vararg types: IElementType): ASTNode? {\n    var node: ASTNode? = this\n    types.forEach {\n        while (node?.hasChildOfType(PARENTHESIZED) == true) {\n            node = node?.findChildByType(PARENTHESIZED)\n        }\n        node = node?.findChildByType(it)\n    }\n    return node\n}\n\n/**\n * @return whether this node is a dot (`.`, `.?`) before a function call or a\n *   property reference.\n * @since 1.2.4\n */\nfun ASTNode.isDotBeforeCallOrReference(): Boolean =\n    elementType in sequenceOf(DOT, SAFE_ACCESS) &&\n            treeNext.elementType in sequenceOf(CALL_EXPRESSION, REFERENCE_EXPRESSION)\n\n/**\n * @return whether this node is an _Elvis_ operation reference (i.e. an\n *   [OPERATION_REFERENCE] which holds [ELVIS] is its only child).\n * @see OPERATION_REFERENCE\n * @see ELVIS\n * @since 1.2.4\n */\nfun ASTNode.isElvisOperationReference(): Boolean =\n    treeParent.elementType == BINARY_EXPRESSION &&\n            elementType == OPERATION_REFERENCE &&\n            run {\n                val children = children().toList()\n                children.size == 1 && children[0].elementType == ELVIS\n            }\n\n/**\n * @return whether this node is a whitespace or a comment.\n * @since 1.2.4\n */\nfun ASTNode.isWhiteSpaceOrComment(): Boolean =\n    isWhiteSpace() || elementType in commentType\n\n/**\n * @return whether this node is a boolean expression (i.e. a [BINARY_EXPRESSION]\n *   holding an [OPERATION_REFERENCE] which, in turn, holds either [ANDAND] or\n *   [OROR] is its only child).\n * @see BINARY_EXPRESSION\n * @see OPERATION_REFERENCE\n * @see ANDAND\n * @see OROR\n * @since 1.2.4\n */\n@Suppress(\n    \"MAGIC_NUMBER\",\n    \"MagicNumber\",\n)\nfun ASTNode.isBooleanExpression(): Boolean =\n    elementType == BINARY_EXPRESSION && run {\n        val operationAndArgs = children().filterNot(ASTNode::isWhiteSpaceOrComment).toList()\n        operationAndArgs.size == 3 && run {\n            val operationReference = operationAndArgs[1]\n            operationReference.elementType == OPERATION_REFERENCE && run {\n                val operations = operationReference.children().toList()\n                operations.size == 1 && operations[0].elementType in sequenceOf(ANDAND, OROR)\n            }\n        }\n    }\n\n/**\n * Before _KtLint_ **0.48**, this extension used to reside in the\n * `com.pinterest.ktlint.core.ast` package.\n * Because _KtLint_ **0.47** has changed the way syntax nodes are traversed (see\n * the diagrams [here](https://github.com/saveourtool/diktat/issues/1538)), the\n * codebase of _KtLint_ no longer needs it: in most cases, it's sufficient to\n * invoke\n *\n * ```kotlin\n * visitor(this)\n * ```\n *\n * and rely on _KtLint_ to invoke the same visitor (which is usually a `Rule`)\n * on this node's children.\n * Still, _Diktat_ sometimes needs exactly this old behaviour.\n *\n * @param visitor the visitor to recursively traverse this node as well as its\n *   children.\n * @since 1.2.5\n */\nfun ASTNode.visit(visitor: AstNodeVisitor<Unit>) {\n    visitor(this)\n    @Suppress(\"NULLABLE_PROPERTY_TYPE\")\n    val filter: TokenSet? = null\n    getChildren(filter).forEach { child ->\n        child.visit(visitor)\n    }\n}\n\n/**\n * @return whether this PSI element is a long string template entry.\n * @since 1.2.4\n */\nfun PsiElement.isLongStringTemplateEntry(): Boolean =\n    node.elementType == LONG_STRING_TEMPLATE_ENTRY\n\n/**\n * Checks that node has child PRIVATE_KEYWORD\n *\n * @return true if node has child PRIVATE_KEYWORD\n */\nfun ASTNode.isPrivate(): Boolean = this.getFirstChildWithType(MODIFIER_LIST)?.getFirstChildWithType(PRIVATE_KEYWORD) != null\n\n/**\n * Checks that node has getter or setter\n *\n * @return true if node has getter or setter\n */\nfun ASTNode.hasSetterOrGetter(): Boolean = this.getFirstChildWithType(KtNodeTypes.PROPERTY_ACCESSOR) != null\n\n/**\n * Checks if ASTNode has parameter `it`\n *\n * @return true if this ASTNode has parameter `it`\n */\nfun ASTNode.hasExplicitIt(): Boolean {\n    require(elementType == LAMBDA_EXPRESSION) { \"Method can be called only for lambda\" }\n    val parameterList = findChildByType(FUNCTION_LITERAL)\n        ?.findChildByType(VALUE_PARAMETER_LIST)\n        ?.psi\n            as KtParameterList?\n    return parameterList?.parameters\n        ?.any { it.name == \"it\" }\n        ?: false\n}\n\nprivate fun ASTNode.isFollowedByNewlineCheck() =\n    this.treeNext.elementType == WHITE_SPACE && this.treeNext.text.contains(\"\\n\")\n\nprivate fun <T> Sequence<T>.takeWhileInclusive(pred: (T) -> Boolean): Sequence<T> {\n    var shouldContinue = true\n    return takeWhile {\n        val result = shouldContinue\n        shouldContinue = pred(it)\n        result\n    }\n}\n\nprivate fun Collection<KtAnnotationEntry>.containSuppressWithName(name: String) =\n    this.any { annotationEntry ->\n        annotationEntry.shortName.toString() == (Suppress::class.simpleName) &&\n                (annotationEntry.valueArgumentList\n                    ?.arguments\n                    ?.any { annotation -> annotation.text.trim('\"') == name }\n                    ?: false)\n    }\n\nprivate fun ASTNode.findOffsetByLine(line: Int, positionByOffset: (Int) -> Pair<Int, Int>): Int {\n    val currentLine = this.getLineNumber()\n    val currentOffset = this.startOffset\n\n    var forwardDirection = true\n\n    // We additionaly consider the offset and line for current node in aim to speed up the search\n    // and not start any time from beginning of file, if possible\n    // If current line is closer to the requested line, start search from it\n    // otherwise search from the beginning of file\n    var lineOffset = if (line < currentLine) {\n        if ((currentLine - line) < line) {\n            forwardDirection = false\n            currentOffset\n        } else {\n            0\n        }\n    } else {\n        currentOffset\n    }\n\n    while (positionByOffset(lineOffset).first != line) {\n        if (forwardDirection) {\n            lineOffset++\n        } else {\n            lineOffset--\n        }\n    }\n    return lineOffset\n}\n\n@Suppress(\"UnsafeCallOnNullableType\")\nprivate fun ASTNode.getAllNodesOnLine(\n    lineOffset: Int,\n    line: Int,\n    positionByOffset: (Int) -> Pair<Int, Int>\n): MutableSet<ASTNode> {\n    val rootNode = this.getRootNode()\n    var beginningOfLineOffset = lineOffset\n    var endOfLineOffset = lineOffset\n\n    while (beginningOfLineOffset > 0 && positionByOffset(beginningOfLineOffset - 1).first == line) {\n        beginningOfLineOffset--\n    }\n\n    while (endOfLineOffset < rootNode.text.length && positionByOffset(endOfLineOffset + 1).first == line) {\n        endOfLineOffset++\n    }\n\n    val nodesSet: MutableSet<ASTNode> = mutableSetOf()\n\n    var currentOffset = beginningOfLineOffset\n    while (currentOffset <= endOfLineOffset) {\n        nodesSet.add(rootNode.psi.findElementAt(currentOffset)!!.node)\n        currentOffset++\n    }\n\n    return nodesSet\n}\n\n/**\n * This function calculates line number instead of using cached values.\n * It should be used when AST could be previously mutated by auto fixers.\n */\nprivate fun ASTNode.calculateLineNumber() = getRootNode()\n    .text\n    .lineSequence()\n    // calculate offset for every line end, `+1` for `\\n` which is trimmed in `lineSequence`\n    .runningFold(0) { acc, line ->\n        acc + line.length + 1\n    }\n    .drop(1)\n    .indexOfFirst {\n        it > startOffset\n    }\n    .let { index ->\n        require(index >= 0) { \"Cannot calculate line number correctly, node's offset $startOffset is greater than file length ${getRootNode().textLength}\" }\n        index + 1\n    }\n\n/**\n * Gets list of property nodes\n *\n * @param node\n * @return list of property nodes\n */\nfun getPropertyNodes(node: ASTNode?): List<ASTNode>? = node?.treeParent?.getAllChildrenWithType(PROPERTY)\n\n/**\n * Checks node is located in file src/test/**/*Test.kt\n *\n * @param testAnchors names of test directories, e.g. \"test\", \"jvmTest\"\n */\nfun isLocatedInTest(filePathParts: List<String>, testAnchors: List<String>) = filePathParts\n    .takeIf { it.contains(PackageNaming.PACKAGE_PATH_ANCHOR) }\n    ?.run { subList(lastIndexOf(PackageNaming.PACKAGE_PATH_ANCHOR), size) }\n    ?.run {\n        // e.g. src/test/ClassTest.kt, other files like src/test/Utils.kt are still checked\n        testAnchors.any { contains(it) } && last().substringBeforeLast('.').endsWith(\"Test\")\n    }\n    ?: false\n\n/**\n * Count number of lines in code block.\n *\n * @return the number of lines in a block of code.\n */\nfun countCodeLines(node: ASTNode): Int {\n    val copyNode = node.clone() as ASTNode\n    copyNode.findAllNodesWithCondition { it.isPartOfComment() }.forEach { it.treeParent.removeChild(it) }\n    val text = copyNode.text.lines().filter { it.isNotBlank() }\n    return text.size\n}\n\n/**\n * Check that lambda contains `it`.\n *\n * @param lambdaNode ASTNode with type LAMBDA_EXPRESSION\n * @return true if `it` contains in lambdaNode.text\n */\nfun hasItInLambda(lambdaNode: ASTNode): Boolean {\n    val excludeChildrenCondition = { node: ASTNode ->\n        node.elementType == LAMBDA_EXPRESSION && (hasNoParameters(node) || node.hasExplicitIt())\n    }\n    val hasIt = lambdaNode\n        .findAllNodesWithCondition(excludeChildrenCondition = excludeChildrenCondition) {\n            it.elementType == REFERENCE_EXPRESSION\n        }\n        .map { it.text }\n        .contains(\"it\")\n\n    return hasIt\n}\n\n/**\n * @param lambdaNode\n * @return true if lambdaNode has no parameters and has `it` in lambdaNode.text\n */\n@Suppress(\"FUNCTION_BOOLEAN_PREFIX\")\nfun doesLambdaContainIt(lambdaNode: ASTNode): Boolean {\n    require(lambdaNode.elementType == LAMBDA_EXPRESSION) { \"Method can be called only for lambda\" }\n    return hasNoParameters(lambdaNode) && hasItInLambda(lambdaNode)\n}\n\n/**\n * Checks that lambda has no parameters\n *\n * @param lambdaNode ASTNode with type LAMBDA_EXPRESSION\n * @return true if node has no parameters\n */\nfun hasNoParameters(lambdaNode: ASTNode): Boolean {\n    require(lambdaNode.elementType == LAMBDA_EXPRESSION) { \"Method can be called only for lambda\" }\n    return null == lambdaNode\n        .findChildByType(FUNCTION_LITERAL)\n        ?.findChildByType(VALUE_PARAMETER_LIST)\n}\n\n/**\n * Checks that property node has pair backing field node or backing field node has pair property node. Nodes make a pair of property node and backing field node if they have:\n * 1. matching names (xyz -> _xyz)\n * 2. same type (but backing field can be nullable),\n * 3. backing field is private\n * 4. backing field should have no accessors/modifiers\n * 5. property should have at least an accessor, or a modifier, or both\n *\n * @param propertyNode if not null, trying to find matching backing field node\n * @param backingFieldNode if not null, trying to find matching property node\n * @return true if node has a pair\n */\n@Suppress(\"CyclomaticComplexMethod\")\ninternal fun isPairPropertyBackingField(propertyNode: KtProperty?, backingFieldNode: KtProperty?): Boolean {\n    val node = (propertyNode ?: backingFieldNode)\n    val propertyList = (node?.parent?.getChildrenOfType<KtProperty>()) ?: return false\n    val nodeType: KtTypeReference? = node.getChildOfType<KtTypeReference>()\n    val nodeNullableType = nodeType?.getChildOfType<KtNullableType>()\n    val nodeName = node.name\n\n    val matchingNode = propertyList.find {pairNode ->\n        val propertyType: KtTypeReference? = pairNode.getChildOfType<KtTypeReference>()\n        // check that property and backing field has same type\n        val sameType = nodeType?.text == propertyType?.text\n\n        // check that property USER_TYPE is same as backing field NULLABLE_TYPE\n        val sameTypeWithNullable = propertyType?.getChildOfType<KtUserType>()?.text ==\n                nodeNullableType?.getChildOfType<KtUserType>()?.text\n\n        // check matching names\n        val propertyName = pairNode.name\n        val matchingNames = propertyNode?.let { nodeName == propertyName?.drop(1) } ?: run { nodeName?.drop(1) == propertyName }\n\n        val isPrivate = propertyNode?.let { pairNode.isPrivate() } ?: run { node.isPrivate() }\n        val noSetterGetterBackingField = propertyNode?.let { !(pairNode.hasCustomSetter() || pairNode.hasCustomGetter()) } ?: run {\n            !(node.hasCustomSetter() || node.hasCustomGetter())\n        }\n        val hasSetterOrGetterProperty = propertyNode?.let { node.hasCustomSetter() || node.hasCustomGetter() } ?: run {\n            pairNode.hasCustomSetter() || pairNode.hasCustomGetter()\n        }\n\n        matchingNames && (sameType || sameTypeWithNullable) && isPrivate &&\n                noSetterGetterBackingField && hasSetterOrGetterProperty\n    }\n    return matchingNode?.let { true } ?: false\n}\n\nprivate fun hasAnySuppressorForInspection(\n    warningName: String,\n    rule: Rule,\n    configs: List<RulesConfig>\n) = { node: ASTNode ->\n    val annotationsForNode = if (node.elementType != KtFileElementType.INSTANCE) {\n        node.findChildByType(MODIFIER_LIST) ?: node.findChildByType(ANNOTATED_EXPRESSION)\n    } else {\n        node.findChildByType(FILE_ANNOTATION_LIST)\n    }\n        ?.findAllDescendantsWithSpecificType(ANNOTATION_ENTRY)\n        ?.map { it.psi as KtAnnotationEntry }\n        ?: emptySet()\n\n    val foundSuppress = annotationsForNode.containSuppressWithName(warningName)\n\n    val foundIgnoredAnnotation =\n        configs.isAnnotatedWithIgnoredAnnotation(rule, annotationsForNode.map { it.shortName.toString() }.toSet())\n\n    val isCompletelyIgnoredBlock = annotationsForNode.containSuppressWithName(DIKTAT)\n\n    foundSuppress || foundIgnoredAnnotation || isCompletelyIgnoredBlock\n}\n"
  },
  {
    "path": "diktat-rules/src/main/kotlin/com/saveourtool/diktat/ruleset/utils/AstNodeUtilsFromKtLint.kt",
    "content": "/**\n * Various utility methods to work with kotlin AST\n * Copied from KtLint for backward compatibility\n */\n\npackage com.saveourtool.diktat.ruleset.utils\n\nimport org.jetbrains.kotlin.com.intellij.lang.ASTNode\nimport org.jetbrains.kotlin.com.intellij.psi.PsiComment\nimport org.jetbrains.kotlin.com.intellij.psi.tree.IElementType\nimport org.jetbrains.kotlin.lexer.KtTokens\nimport org.jetbrains.kotlin.psi.psiUtil.parents\nimport org.jetbrains.kotlin.psi.psiUtil.siblings\nimport org.jetbrains.kotlin.psi.stubs.elements.KtFileElementType\n\n/**\n * @return true if current [ASTNode] is root\n */\nfun ASTNode.isRoot(): Boolean = elementType == KtFileElementType.INSTANCE\n\n/**\n * @return true if current [ASTNode] is a leaf\n */\nfun ASTNode.isLeaf(): Boolean = firstChildNode == null\n\n/**\n * @return true if this [ASTNode] is [KtTokens.WHITE_SPACE] and contains '\\n'\n */\nfun ASTNode?.isWhiteSpaceWithNewline(): Boolean = this?.elementType == KtTokens.WHITE_SPACE && this?.textContains('\\n') == true\n\n/**\n * @param strict true if it doesn't need to check current [ASTNode]\n * @param predicate\n * @return first parent which meets [predicate] condition\n */\nfun ASTNode.parent(\n    strict: Boolean = true,\n    predicate: (ASTNode) -> Boolean,\n): ASTNode? = if (!strict && predicate(this)) {\n    this\n} else {\n    parents().firstOrNull(predicate)\n}\n\n/**\n * @param elementType [IElementType]\n * @param strict\n */\nfun ASTNode.parent(\n    elementType: IElementType,\n    strict: Boolean = true,\n): ASTNode? = parent(strict) { it.elementType == elementType }\n\n/**\n * @return true if current [ASTNode] is [KtTokens.WHITE_SPACE]\n */\nfun ASTNode?.isWhiteSpace(): Boolean = this?.elementType == KtTokens.WHITE_SPACE\n\n/**\n * @return true if current [ASTNode] is not part of a comment\n */\nfun ASTNode.isPartOfComment(): Boolean = parent(strict = false) { it.psi is PsiComment } != null\n\n/**\n * @return previous sibling [ASTNode] which is code\n */\nfun ASTNode.prevCodeSibling(): ASTNode? = prevSibling { it.isCode() }\n\n/**\n * @param predicate\n * @return previous sibling [ASTNode] which matches [predicate]\n */\ninline fun ASTNode.prevSibling(predicate: (ASTNode) -> Boolean = { true }): ASTNode? = siblings(false).firstOrNull(predicate)\n\n/**\n * @return next sibling [ASTNode] which is code\n */\nfun ASTNode.nextCodeSibling(): ASTNode? = nextSibling { it.isCode() }\n\n/**\n * @param predicate\n * @return [ASTNode] next sibling which matches [predicate]\n */\ninline fun ASTNode.nextSibling(predicate: (ASTNode) -> Boolean = { true }): ASTNode? = siblings(true).firstOrNull(predicate)\n\n/**\n * @return next [ASTNode] which is a code leaf\n */\nfun ASTNode.nextCodeLeaf(): ASTNode? = generateSequence(nextLeaf()) { it.nextLeaf() }\n    .firstOrNull {\n        it.isCode()\n    }\n\n/**\n * @param elementType\n * @return true if current [ASTNode] has a parent with [elementType]\n */\nfun ASTNode.isPartOf(elementType: IElementType): Boolean = parent(elementType, strict = false) != null\n\nprivate fun ASTNode.nextLeaf(): ASTNode? = generateSequence(nextLeafAny()) { it.nextLeafAny() }\n    .firstOrNull { it.textLength != 0 }\n\nprivate fun ASTNode.nextLeafAny(): ASTNode? = firstChildLeaf() ?: nextLeafStrict()\n\nprivate fun ASTNode.nextLeafStrict(): ASTNode? = treeNext?.firstChildLeafOrSelf() ?: treeParent?.nextLeafStrict()\n\nprivate fun ASTNode.firstChildLeafOrSelf(): ASTNode = firstChildLeaf() ?: this\n\nprivate fun ASTNode.firstChildLeaf(): ASTNode? = generateSequence(firstChildNode, ASTNode::getFirstChildNode)\n    .lastOrNull()\n\nprivate fun ASTNode.isCode(): Boolean = !isWhiteSpace() && !isPartOfComment()\n"
  },
  {
    "path": "diktat-rules/src/main/kotlin/com/saveourtool/diktat/ruleset/utils/FileUtils.kt",
    "content": "/**\n * Utility methods to work with file paths.\n */\n\npackage com.saveourtool.diktat.ruleset.utils\n\ninternal const val SRC_DIRECTORY_NAME = \"src\"\n\n/**\n * Splits [this] string by file path separator.\n *\n * @return list of path parts\n */\nfun String.splitPathToDirs(): List<String> =\n    this.replace(\"\\\\\", \"/\")\n        .replace(\"//\", \"/\")\n        .split(\"/\")\n\n/**\n * Checks if [this] String is a name of a gradle kotlin script file by checking whether file extension equals 'gradle.kts'\n *\n * @return true if this is a gradle kotlin script file name, false otherwise\n */\nfun String.isGradleScript() = endsWith(\"gradle.kts\")\n"
  },
  {
    "path": "diktat-rules/src/main/kotlin/com/saveourtool/diktat/ruleset/utils/FunctionAstNodeUtils.kt",
    "content": "/**\n * Various utility methods to work with AST nodes containing functions\n */\n\npackage com.saveourtool.diktat.ruleset.utils\n\nimport org.jetbrains.kotlin.KtNodeTypes\nimport org.jetbrains.kotlin.KtNodeTypes.BLOCK\nimport org.jetbrains.kotlin.com.intellij.lang.ASTNode\nimport org.jetbrains.kotlin.psi.KtFunction\n\n/**\n * @return whether the function has any parameters\n */\nfun ASTNode.hasParameters(): Boolean {\n    checkNodeIsFun(this)\n    val argList = this.argList()\n    return argList != null && argList.hasChildOfType(KtNodeTypes.VALUE_PARAMETER)\n}\n\n/**\n * @return names of function parameters as Strings\n */\nfun ASTNode.parameterNames(): Collection<String?> {\n    checkNodeIsFun(this)\n    return (psi as KtFunction).valueParameters.map { it.name }\n}\n\n/**\n * Returns list of lines of this function body, excluding opening and closing braces if they are on separate lines\n *\n * @return function body text as a list of strings\n */\nfun ASTNode.getBodyLines(): List<String> {\n    checkNodeIsFun(this)\n    return this.getFirstChildWithType(BLOCK)?.let { blockNode ->\n        blockNode.text\n            .lines()\n            .let { if (it.first().matches(\"\\\\{\\\\s*\".toRegex())) it.drop(1) else it }\n            .let { if (it.last().matches(\"\\\\s*}\".toRegex())) it.dropLast(1) else it }\n    } ?: emptyList()\n}\n\n/**\n * @return if this function is getter or setter according to it's signature\n */\nfun ASTNode.isGetterOrSetter(): Boolean {\n    checkNodeIsFun(this)\n    return getIdentifierName()?.let { functionName ->\n        when {\n            functionName.text.startsWith(SET_PREFIX) -> parameterNames().size == 1\n            functionName.text.startsWith(GET_PREFIX) -> parameterNames().isEmpty()\n            else -> false\n        }\n    } ?: false\n}\n\n/**\n * @return whether this function is a standard method\n */\nfun ASTNode.isStandardMethod() = also(::checkNodeIsFun)\n    .getIdentifierName()\n    ?.let { it.text in standardMethods }\n    ?: false\n\nprivate fun ASTNode.argList(): ASTNode? {\n    checkNodeIsFun(this)\n    return this.getFirstChildWithType(KtNodeTypes.VALUE_PARAMETER_LIST)\n}\n\nprivate fun checkNodeIsFun(node: ASTNode) =\n    require(node.elementType == KtNodeTypes.FUN) {\n        \"This utility method operates on nodes of type ElementType.FUN only\"\n    }\n"
  },
  {
    "path": "diktat-rules/src/main/kotlin/com/saveourtool/diktat/ruleset/utils/KdocUtils.kt",
    "content": "/**\n * Various utility methods to work with KDoc representation in AST\n */\n\npackage com.saveourtool.diktat.ruleset.utils\n\nimport org.jetbrains.kotlin.com.intellij.lang.ASTNode\nimport org.jetbrains.kotlin.com.intellij.psi.impl.source.tree.CompositeElement\nimport org.jetbrains.kotlin.com.intellij.psi.impl.source.tree.LeafPsiElement\nimport org.jetbrains.kotlin.com.intellij.psi.impl.source.tree.PsiWhiteSpaceImpl\nimport org.jetbrains.kotlin.kdoc.lexer.KDocTokens\nimport org.jetbrains.kotlin.kdoc.parser.KDocElementTypes\nimport org.jetbrains.kotlin.kdoc.parser.KDocKnownTag\nimport org.jetbrains.kotlin.kdoc.psi.impl.KDocTag\nimport org.jetbrains.kotlin.lexer.KtTokens.WHITE_SPACE\n\n/**\n * @return a list of [KDocTag]s from this KDoc node\n */\nfun ASTNode.kDocTags(): List<KDocTag> {\n    require(this.elementType == KDocTokens.KDOC) { \"kDoc tags can be retrieved only from KDOC node\" }\n    return this.getAllChildrenWithType(KDocElementTypes.KDOC_SECTION).flatMap { sectionNode ->\n        sectionNode.getAllChildrenWithType(KDocElementTypes.KDOC_TAG)\n            .map { its -> its.psi as KDocTag }\n    }\n}\n\n/**\n * @param knownTag a tag to look for\n * @return whether this tag is present\n */\nfun Iterable<KDocTag>.hasKnownKdocTag(knownTag: KDocKnownTag): Boolean =\n    this.any { it.knownTag == knownTag }\n\n/**\n * Checks for trailing newlines in tag's body. Handles cases, when there is no leading asterisk on an empty line:\n * ```\n * * @param param\n *\n * * @return\n * ```\n * as well as usual simple cases.\n *\n * @return true if there is a trailing newline\n */\nfun KDocTag.hasTrailingNewlineInTagBody() = node.lastChildNode.isWhiteSpaceWithNewline() ||\n        node.reversedChildren()\n            .takeWhile { it.elementType == WHITE_SPACE || it.elementType == KDocTokens.LEADING_ASTERISK }\n            .firstOrNull { it.elementType == KDocTokens.LEADING_ASTERISK }\n            ?.takeIf { it.treeNext == null || it.treeNext.elementType == WHITE_SPACE } != null\n\n/**\n * This method inserts a new tag into KDoc before specified another tag, aligning it with the rest of this KDoc\n *\n * @param beforeTag tag before which the new one will be placed\n * @param consumer lambda which should be used to fill new tag with data, accepts CompositeElement as an argument\n */\n@Suppress(\"UnsafeCallOnNullableType\")\ninline fun ASTNode.insertTagBefore(\n    beforeTag: ASTNode?,\n    consumer: CompositeElement.() -> Unit\n) {\n    require(this.elementType == KDocTokens.KDOC && this.hasChildOfType(KDocElementTypes.KDOC_SECTION)) { \"kDoc tags can be inserted only into KDOC node\" }\n    val kdocSection = this.getFirstChildWithType(KDocElementTypes.KDOC_SECTION)!!\n    val newTag = CompositeElement(KDocElementTypes.KDOC_TAG)\n    val beforeTagLineStart = beforeTag?.prevSibling {\n        it.elementType == WHITE_SPACE && it.treeNext?.elementType == KDocTokens.LEADING_ASTERISK\n    }\n    val indent = this\n        .getFirstChildWithType(WHITE_SPACE)\n        ?.text\n        ?.split(\"\\n\")\n        ?.last() ?: \"\"\n    kdocSection.addChild(PsiWhiteSpaceImpl(\"\\n$indent\"), beforeTagLineStart)\n    kdocSection.addChild(LeafPsiElement(KDocTokens.LEADING_ASTERISK, \"*\"), beforeTagLineStart)\n    kdocSection.addChild(LeafPsiElement(KDocTokens.TEXT, \" \"), beforeTagLineStart)\n    kdocSection.addChild(newTag, beforeTagLineStart)\n    consumer(newTag)\n}\n"
  },
  {
    "path": "diktat-rules/src/main/kotlin/com/saveourtool/diktat/ruleset/utils/KotlinParseException.kt",
    "content": "package com.saveourtool.diktat.ruleset.utils\n\n/**\n * An [Exception] that can be thrown during parsing of kotlin code\n */\nclass KotlinParseException(message: String) : Exception(message)\n"
  },
  {
    "path": "diktat-rules/src/main/kotlin/com/saveourtool/diktat/ruleset/utils/KotlinParser.kt",
    "content": "package com.saveourtool.diktat.ruleset.utils\n\nimport org.jetbrains.kotlin.KtNodeTypes.BLOCK\nimport org.jetbrains.kotlin.KtNodeTypes.IMPORT_LIST\nimport org.jetbrains.kotlin.cli.common.environment.setIdeaIoUseFallback\nimport org.jetbrains.kotlin.cli.common.messages.MessageCollector\nimport org.jetbrains.kotlin.cli.jvm.compiler.EnvironmentConfigFiles\nimport org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment\nimport org.jetbrains.kotlin.com.intellij.lang.ASTNode\nimport org.jetbrains.kotlin.com.intellij.mock.MockProject\nimport org.jetbrains.kotlin.com.intellij.openapi.project.Project\nimport org.jetbrains.kotlin.com.intellij.openapi.util.UserDataHolderBase\nimport org.jetbrains.kotlin.com.intellij.pom.PomModel\nimport org.jetbrains.kotlin.com.intellij.pom.PomModelAspect\nimport org.jetbrains.kotlin.com.intellij.pom.PomTransaction\nimport org.jetbrains.kotlin.com.intellij.pom.impl.PomTransactionBase\nimport org.jetbrains.kotlin.com.intellij.pom.tree.TreeAspect\nimport org.jetbrains.kotlin.com.intellij.psi.TokenType.ERROR_ELEMENT\nimport org.jetbrains.kotlin.config.CommonConfigurationKeys\nimport org.jetbrains.kotlin.config.CompilerConfiguration\nimport org.jetbrains.kotlin.lexer.KtTokens\nimport org.jetbrains.kotlin.lexer.KtTokens.IMPORT_KEYWORD\nimport org.jetbrains.kotlin.psi.KtPsiFactory\nimport org.jetbrains.kotlin.resolve.ImportPath\nimport sun.reflect.ReflectionFactory\n\n/**\n * A class that wraps kotlin compiler's code parser and converts source code into AST\n */\nclass KotlinParser {\n    private val project: Project by lazy {\n        val compilerConfiguration = CompilerConfiguration()\n        compilerConfiguration.put(CommonConfigurationKeys.MESSAGE_COLLECTOR_KEY, MessageCollector.NONE)  // mute the output logging to process it themselves\n        val pomModel: PomModel = object : UserDataHolderBase(), PomModel {\n            override fun runTransaction(transaction: PomTransaction) {\n                (transaction as PomTransactionBase).run()\n            }\n\n            @Suppress(\"UNCHECKED_CAST\", \"SpreadOperator\")\n            override fun <T : PomModelAspect> getModelAspect(aspect: Class<T>): T? {\n                if (aspect == TreeAspect::class.java) {\n                    val constructor = ReflectionFactory.getReflectionFactory().newConstructorForSerialization(\n                        aspect,\n                        Any::class.java.getDeclaredConstructor(*arrayOfNulls<Class<*>>(0))\n                    )\n                    return constructor.newInstance() as T\n                }\n                return null\n            }\n        }  // I don't really understand what's going on here, but thanks to this, you can use this node in the future\n        val project = KotlinCoreEnvironment.createForProduction({},\n            compilerConfiguration,\n            EnvironmentConfigFiles.JVM_CONFIG_FILES\n        ).project  // create project\n        project as MockProject\n        project.registerService(PomModel::class.java, pomModel)\n        project\n    }\n    private val ktPsiFactory by lazy { KtPsiFactory(project, true) }\n\n    /**\n     * Set idea.io.use.nio2 in system property to true\n     * fixme Maybe should check OS to don't change system property\n     */\n    init {\n        setIdeaIoUseFallback()\n    }\n\n    /**\n     * @param text kotlin code\n     * @param isPackage whether resulting node should be a package directive\n     * @return [ASTNode]\n     * @throws KotlinParseException if code is incorrect\n     */\n    fun createNode(text: String, isPackage: Boolean = false) = makeNode(text, isPackage) ?: throw KotlinParseException(\"Text is not valid: [$text]\")\n\n    /**\n     * @param text kotlin code\n     * @return [ASTNode] which is secondary constructor\n     * @throws KotlinParseException if code is incorrect\n     */\n    @Suppress(\"SAY_NO_TO_VAR\")\n    fun createNodeForSecondaryConstructor(text: String): ASTNode {\n        val node: ASTNode = ktPsiFactory\n            .createSecondaryConstructor(text)\n            .node\n        if (!node.isCorrect()) {\n            throw KotlinParseException(\"Text is not valid: [$text]\")\n        }\n        return node\n    }\n\n    /**\n     * @param text kotlin code\n     * @return [ASTNode] which is init block\n     * @throws KotlinParseException if code is incorrect\n     */\n    @Suppress(\n        \"SAY_NO_TO_VAR\",\n        \"UnsafeCallOnNullableType\"\n    )\n    fun createNodeForInit(text: String): ASTNode {\n        val node: ASTNode = ktPsiFactory\n            .createBlockCodeFragment(text, null)\n            .node\n            .findChildByType(BLOCK)!!\n            .firstChildNode\n        if (!node.isCorrect()) {\n            throw KotlinParseException(\"Text is not valid: [$text]\")\n        }\n        return node\n    }\n\n    /**\n     * @param text kotlin code\n     * @return [KtPrimaryConstructor]\n     */\n    fun createPrimaryConstructor(text: String) = ktPsiFactory.createPrimaryConstructor(text)\n\n    /**\n     * This method create a node based on text.\n     *\n     * @param isPackage - flag to check if node will contains package.\n     * If this flag is true, node's element type will be FILE.\n     * Else, try to create node based on text.\n     * If this node will contain ERROR_ELEMENT type children this mean that cannot create node based on this text\n     */\n    @Suppress(\n        \"UnsafeCallOnNullableType\",\n        \"TOO_LONG_FUNCTION\",\n        \"SAY_NO_TO_VAR\"\n    )\n    private fun makeNode(text: String, isPackage: Boolean = false): ASTNode? {\n        if (text.isEmpty()) {\n            return null\n        }\n        if (text.trim().isEmpty()) {\n            return ktPsiFactory.createWhiteSpace(text).node\n        }\n        var node: ASTNode = if (isPackage || isContainKdoc(text)) {\n            ktPsiFactory.createFile(text).node\n        } else if (text.contains(KtTokens.IMPORT_KEYWORD.value)) {\n            val (imports, blockCode) = text.lines().partition { it.contains(KtTokens.IMPORT_KEYWORD.value) }\n            when {\n                blockCode.isNotEmpty() -> return null\n                imports.size == 1 -> {\n                    val importText = ImportPath.fromString(text.substringAfter(\"$IMPORT_KEYWORD \"))\n                    ktPsiFactory.createImportDirective(importText).node\n                }\n                else -> ktPsiFactory\n                    .createBlockCodeFragment(text, null)\n                    .node\n                    .findChildByType(BLOCK)!!\n                    .findChildByType(ERROR_ELEMENT)!!\n                    .findChildByType(IMPORT_LIST)!!\n            }\n        } else {\n            ktPsiFactory\n                .createBlockCodeFragment(text, null)\n                .node\n                .findChildByType(BLOCK)!!\n        }\n        if (node.getChildren(null).size == 1) {\n            node = node.firstChildNode\n        }\n        if (!node.isCorrect()) {\n            node = ktPsiFactory.createFile(text).node\n            if (!node.isCorrect()) {\n                return null\n            }\n        }\n        return node\n    }\n\n    private fun isContainKdoc(text: String) =\n        text.lines().any { it.trim().startsWith(\"/**\") }\n}\n"
  },
  {
    "path": "diktat-rules/src/main/kotlin/com/saveourtool/diktat/ruleset/utils/PositionInTextLocator.kt",
    "content": "/**\n * Code to create fast mapping of text offset tol ine and column numbers\n * fixme: this code is copy-pasted from ktlint. Change it\n */\n\npackage com.saveourtool.diktat.ruleset.utils\n\ninternal typealias LineAndColumn = Pair<Int, Int>\n\n@Suppress(\n    \"MISSING_KDOC_ON_FUNCTION\",\n    \"KDOC_WITHOUT_PARAM_TAG\",\n    \"KDOC_WITHOUT_RETURN_TAG\"\n)\nprivate class SegmentTree(sortedArray: IntArray) {\n    private val segments: List<Segment> = sortedArray\n        .dropLast(1)\n        .mapIndexed { index: Int, element: Int ->\n            Segment(element, sortedArray[index + 1] - 1)\n        }\n\n    init {\n        require(sortedArray.size > 1) { \"At least two data points are required\" }\n        sortedArray.reduce { current, next ->\n            require(current <= next) { \"Data points are not sorted (ASC)\" }\n            next\n        }\n    }\n\n    fun get(index: Int): Segment = segments[index]\n\n    fun indexOf(index: Int): Int = binarySearch(index, 0, segments.size - 1)\n\n    private fun binarySearch(\n        compareElement: Int,\n        left: Int,\n        right: Int\n    ): Int = when {\n        left > right -> -1\n        else -> {\n            val index = left + (right - left) / 2\n            val midElement = segments[index]\n            if (compareElement < midElement.left) {\n                binarySearch(compareElement, left, index - 1)\n            } else {\n                if (midElement.right < compareElement) binarySearch(compareElement, index + 1, right) else index\n            }\n        }\n    }\n}\n\n@Suppress(\"KDOC_NO_CONSTRUCTOR_PROPERTY\")\nprivate data class Segment(\n    val left: Int,\n    val right: Int\n)\n\n/**\n * Calculate position in text - line and column based on offset from the text start.\n *\n * @param text a piece of text\n * @return mapping function from offset to line and column number\n */\ninternal fun buildPositionInTextLocator(text: String): (offset: Int) -> LineAndColumn {\n    val textLength = text.length\n    val identifierArray: ArrayList<Int> = ArrayList()\n    var endOfLineIndex = -1\n\n    do {\n        identifierArray.add(endOfLineIndex + 1)\n        endOfLineIndex = text.indexOf('\\n', endOfLineIndex + 1)\n    } while (endOfLineIndex != -1)\n\n    identifierArray.add(textLength + if (identifierArray.last() == textLength) 1 else 0)\n\n    val segmentTree = SegmentTree(identifierArray.toIntArray())\n\n    return { offset ->\n        val line = segmentTree.indexOf(offset)\n        if (line != -1) {\n            val column = offset - segmentTree.get(line).left\n            line + 1 to column + 1\n        } else {\n            1 to 1\n        }\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/main/kotlin/com/saveourtool/diktat/ruleset/utils/PsiUtils.kt",
    "content": "/**\n * Utility methods to work with PSI code representation\n */\n\npackage com.saveourtool.diktat.ruleset.utils\n\nimport org.jetbrains.kotlin.psi.KtBinaryExpression\nimport org.jetbrains.kotlin.psi.KtBlockExpression\nimport org.jetbrains.kotlin.psi.KtCallExpression\nimport org.jetbrains.kotlin.psi.KtConstantExpression\nimport org.jetbrains.kotlin.psi.KtDotQualifiedExpression\nimport org.jetbrains.kotlin.psi.KtExpression\nimport org.jetbrains.kotlin.psi.KtNameReferenceExpression\nimport org.jetbrains.kotlin.psi.KtProperty\nimport org.jetbrains.kotlin.psi.KtReferenceExpression\nimport org.jetbrains.kotlin.psi.KtStringTemplateExpression\nimport org.jetbrains.kotlin.psi.psiUtil.getParentOfType\nimport org.jetbrains.kotlin.psi.psiUtil.isAncestor\nimport org.jetbrains.kotlin.psi.psiUtil.parents\n\n/**\n * Checks if this [KtExpression] contains only constant literals, strings with possibly constant expressions in templates,\n * method calls on literals.\n *\n * @return boolean result\n */\n@Suppress(\"UnsafeCallOnNullableType\", \"FUNCTION_BOOLEAN_PREFIX\")\nfun KtExpression.containsOnlyConstants(): Boolean =\n    when (this) {\n        is KtConstantExpression -> true\n        is KtStringTemplateExpression -> entries.all { it.expression?.containsOnlyConstants() ?: true }\n        // left and right are marked @Nullable @IfNotParsed, so it should be safe to `!!`\n        is KtBinaryExpression -> left!!.containsOnlyConstants() && right!!.containsOnlyConstants()\n        is KtDotQualifiedExpression -> receiverExpression.containsOnlyConstants() &&\n                (selectorExpression is KtReferenceExpression ||\n                        ((selectorExpression as? KtCallExpression)\n                            ?.valueArgumentList\n                            ?.arguments\n                            ?.all { it.getArgumentExpression()!!.containsOnlyConstants() }\n                            ?: false)\n                )\n        else -> false\n    }\n\n/**\n * Get block inside which the property is declared.\n * Here we assume that property can be declared only in block, since declaration is not an expression in kotlin\n * and compiler prohibits things like `if (condition) val x = 0`.\n */\nfun KtProperty.getDeclarationScope() =\n    // FixMe: class body is missing here\n    getParentOfType<KtBlockExpression>(true)\n\n/**\n * Method that tries to find a local property declaration with the same name as current [KtNameReferenceExpression] element\n *\n * @return [KtProperty] if it is found, null otherwise\n */\nfun KtNameReferenceExpression.findLocalDeclaration(): KtProperty? = parents\n    .mapNotNull { it as? KtBlockExpression }\n    .mapNotNull { blockExpression ->\n        blockExpression\n            .statements\n            .takeWhile { !it.isAncestor(this, true) }\n            .mapNotNull { it as? KtProperty }\n            .find {\n                it.isLocal &&\n                        it.hasInitializer() &&\n                        it.name?.equals(getReferencedName())\n                        ?: false\n            }\n    }\n    .firstOrNull()\n\n/**\n * @return name of a function which is called in a [KtCallExpression] or null if it can't be found\n */\nfun KtCallExpression.getFunctionName() = (calleeExpression as? KtNameReferenceExpression)?.getReferencedName()\n"
  },
  {
    "path": "diktat-rules/src/main/kotlin/com/saveourtool/diktat/ruleset/utils/StringCaseUtils.kt",
    "content": "@file:Suppress(\"FILE_NAME_MATCH_CLASS\", \"MatchingDeclarationName\")\n\npackage com.saveourtool.diktat.ruleset.utils\n\nimport com.google.common.base.CaseFormat\nimport io.github.oshai.kotlinlogging.KotlinLogging\n\nimport java.util.Locale\n\nprivate val log = KotlinLogging.logger {}\n\n/**\n * Available cases to name enum members\n * @property str\n */\nenum class Style(val str: String) {\n    PASCAL_CASE(\"PascalCase\"),\n    SNAKE_CASE(\"UPPER_SNAKE_CASE\"),\n    ;\n}\n\n/**\n * checking that string looks like: PascalCaseForClassName\n *\n * @return boolean result\n */\nfun String.isPascalCase(): Boolean = this.matches(\"([A-Z][a-z0-9]+)+\".toRegex())\n\n/**\n * checking that string looks like: lowerCaseOfVariable\n *\n * @return boolean result\n */\nfun String.isLowerCamelCase(): Boolean = this.matches(\"[a-z]([a-z0-9])*([A-Z][a-z0-9]+)*\".toRegex())\n\n/**\n * checking that string looks like: CORRECT_CASE_FOR_CONSTANTS\n *\n * @return boolean result\n */\nfun String.isUpperSnakeCase(): Boolean = this.matches(\"(([A-Z0-9]+)_*)+[A-Z0-9]*\".toRegex())\n\n/**\n * checking that string looks like: lower_case_for_script_names\n *\n * @return boolean result\n */\nfun String.isLowerSnakeCase(): Boolean = this.matches(\"(([a-z]+)_*)+[a-z0-9]*\".toRegex())\n\n/**\n * detecting the case of _this_ String and converting it to the right UpperSnakeCase (UPPER_UNDERSCORE) case\n *\n * @return converted string\n */\nfun String.toUpperSnakeCase(): String {\n    // PascalCase -> PASCAL_CASE\n    if (this.isPascalCase()) {\n        return CaseFormat.UPPER_CAMEL.to(CaseFormat.UPPER_UNDERSCORE, this)\n    }\n    // lower -> LOWER\n    if (this.all { it.isLowerCase() }) {\n        return this.uppercase(Locale.getDefault())\n    }\n    // lowerCamel -> LOWER_CAMEL\n    if (this.isLowerCamelCase()) {\n        return CaseFormat.LOWER_CAMEL.to(CaseFormat.UPPER_UNDERSCORE, this)\n    }\n    // lower_snake -> LOWER_SNAKE\n    if (this.isLowerSnakeCase()) {\n        return CaseFormat.LOWER_UNDERSCORE.to(CaseFormat.UPPER_UNDERSCORE, this)\n    }\n\n    val idx = getFirstLetterOrDigit()\n    if (idx != -1) {\n        // any other format -> UPPER_SNAKE_CASE\n        // [p]a[SC]a[_]l -> [P]A_[SC]_A_[L]\n        return this[idx].uppercaseChar().toString() + convertUnknownCaseToUpperSnake(this.substring(idx + 1))\n    }\n\n    log.error { \"Not able to fix case format for: $this\" }\n    return this\n}\n\n/**\n * detecting the case of _this_ String and converting it to the right UpperSnakeCase (UPPER_UNDERSCORE) case\n *\n * @return converted string\n */\n@Suppress(\"ForbiddenComment\")\nfun String.toLowerCamelCase(): String {\n    // PascalCase -> PASCAL_CASE\n    if (this.isPascalCase()) {\n        return CaseFormat.UPPER_CAMEL.to(CaseFormat.LOWER_CAMEL, this)\n    }\n    // lower -> LOWER\n    if (this.all { it.isUpperCase() }) {\n        return this.lowercase(Locale.getDefault())\n    }\n    // lowerCamel -> LOWER_CAMEL\n    if (this.isUpperSnakeCase()) {\n        return CaseFormat.UPPER_UNDERSCORE.to(CaseFormat.LOWER_CAMEL, this)\n    }\n    // lower_snake -> LOWER_SNAKE\n    if (this.isLowerSnakeCase()) {\n        return CaseFormat.LOWER_UNDERSCORE.to(CaseFormat.LOWER_CAMEL, this)\n    }\n\n    val idx = getFirstLetterOrDigit()\n    if (idx != -1) {\n        // any other format -> camelCase\n        // changing first letter to uppercase and replacing several uppercase letters in raw to lowercase:\n        // example of change: [P]a[SC]a[_]l -> [p]a[Sc]a[L]\n        // FixMe: there is some discussion on how lowerN_Case should be resolved: to lowerNcase or to lowernCase or lowerNCase (current version)\n        return this[idx].lowercaseChar().toString() + convertUnknownCaseToCamel(this.substring(idx + 1), this[idx].isUpperCase())\n    }\n\n    log.error { \"Not able to fix case format for: $this\" }\n    return this\n}\n\n/**\n * detecting the case of _this_ String and converting it to the right PascalCase (UpperCamel) case\n *\n * @return converted string\n */\n@Suppress(\"ForbiddenComment\")\nfun String.toPascalCase(): String = when {\n    all { it.isUpperCase() } -> {\n        // all letters UPPER -> Upper\n        this[0] + substring(1).lowercase(Locale.getDefault())\n    }\n    all { it.isLowerCase() } -> {\n        // all letters lower -> Lower\n        this[0].uppercaseChar() + substring(1)\n    }\n    isUpperSnakeCase() -> {\n        // lowerCamel -> LowerCamel\n        CaseFormat.UPPER_UNDERSCORE.to(CaseFormat.UPPER_CAMEL, this)\n    }\n    isLowerSnakeCase() -> {\n        // lower_snake -> LowerSnake\n        CaseFormat.LOWER_UNDERSCORE.to(CaseFormat.UPPER_CAMEL, this)\n    }\n    else -> {\n        val idx = getFirstLetterOrDigit()\n        if (idx != -1) {\n            // any other format -> PascalCase\n            // changing first letter to uppercase and replacing several uppercase letters in raw to lowercase:\n            // example of change: [p]a[SC]a[_]l -> [P]a[Sc]a[L]\n            // FixMe: there is some discussion on how PascalN_Case should be resolved: to PascalNcase or to PascalnCase or PascalNCase (current version)\n            this[idx].uppercaseChar().toString() + convertUnknownCaseToCamel(substring(idx + 1), true)\n        } else {\n            log.error { \"Not able to fix case format for: $this\" }\n            this\n        }\n    }\n}\n\n/**\n * @return index of first character which is a letter or a digit\n */\nprivate fun String.getFirstLetterOrDigit() =\n    indexOfFirst { it.isLetterOrDigit() }\n\nprivate fun convertUnknownCaseToCamel(str: String, isFirstLetterCapital: Boolean): String {\n    // [p]a[SC]a[_]l -> [P]a[Sc]a[L]\n    var isPreviousLetterCapital = isFirstLetterCapital\n    var isPreviousLetterUnderscore = false\n    return str.map { char ->\n        if (char.isUpperCase()) {\n            val result = if (isPreviousLetterCapital && !isPreviousLetterUnderscore) char.lowercaseChar() else char\n            isPreviousLetterCapital = true\n            isPreviousLetterUnderscore = false\n            result.toString()\n        } else {\n            val result = when {\n                char == '_' -> {\n                    isPreviousLetterUnderscore = true\n                    \"\"\n                }\n                isPreviousLetterUnderscore -> {\n                    isPreviousLetterCapital = true\n                    isPreviousLetterUnderscore = false\n                    char.uppercaseChar().toString()\n                }\n                else -> {\n                    isPreviousLetterCapital = false\n                    isPreviousLetterUnderscore = false\n                    char.toString()\n                }\n            }\n            result\n        }\n    }.joinToString(\"\")\n}\n\nprivate fun convertUnknownCaseToUpperSnake(str: String): String {\n    // [p]a[SC]a[_]l -> [P]A_[SC]_A_[L]\n    var alreadyInsertedUnderscore = true\n    return str.map { char ->\n        if (char.isUpperCase()) {\n            if (!alreadyInsertedUnderscore) {\n                alreadyInsertedUnderscore = true\n                \"_$char\"\n            } else {\n                char.toString()\n            }\n        } else {\n            alreadyInsertedUnderscore = (char == '_')\n            char.uppercaseChar().toString()\n        }\n    }.joinToString(\"\")\n}\n"
  },
  {
    "path": "diktat-rules/src/main/kotlin/com/saveourtool/diktat/ruleset/utils/StringUtils.kt",
    "content": "/**\n * Utility methods and constants to work with strings\n */\n\npackage com.saveourtool.diktat.ruleset.utils\n\nimport org.jetbrains.kotlin.lexer.KtTokens\n\ninternal const val NEWLINE = '\\n'\n\ninternal const val SPACE = ' '\n\ninternal const val TAB = '\\t'\n\n@Suppress(\"VARIABLE_NAME_INCORRECT_FORMAT\")\nval JAVA = arrayOf(\"abstract\", \"assert\", \"boolean\",\n    \"break\", \"byte\", \"case\", \"catch\", \"char\", \"class\", \"const\",\n    \"continue\", \"default\", \"do\", \"double\", \"else\", \"extends\", \"false\",\n    \"final\", \"finally\", \"float\", \"for\", \"goto\", \"if\", \"implements\",\n    \"import\", \"instanceof\", \"int\", \"interface\", \"long\", \"native\",\n    \"new\", \"null\", \"package\", \"private\", \"protected\", \"public\",\n    \"return\", \"short\", \"static\", \"strictfp\", \"super\", \"switch\",\n    \"synchronized\", \"this\", \"throw\", \"throws\", \"transient\", \"true\",\n    \"try\", \"void\", \"volatile\", \"while\")\n\n@Suppress(\"VARIABLE_NAME_INCORRECT_FORMAT\")\nval KOTLIN = KtTokens.KEYWORDS\n    .types\n    .map { line -> line.toString() }\n    .plus(KtTokens.SOFT_KEYWORDS.types.map { line -> line.toString() })\n\n/**\n * Either `log` or `logger`, case-insensitive.\n *\n * A name like `psychologist` or `LOGIN` won't be matched by this regular\n * expression.\n */\nval loggerPropertyRegex = \"(?iu)^log(?:ger)?$\".toRegex()\n\n/**\n * @return whether [this] string represents a Java keyword\n */\nfun String.isJavaKeyWord() = JAVA.contains(this)\n\n/**\n * @return whether [this] string represents a Kotlin keyword\n */\nfun String.isKotlinKeyWord() = KOTLIN.contains(this)\n\n/**\n * @return whether [this] string contains only ASCII letters and/or digits\n */\n@Suppress(\"FUNCTION_NAME_INCORRECT_CASE\")\nfun String.isASCIILettersAndDigits(): Boolean = this.all { it.isDigit() || it in 'A'..'Z' || it in 'a'..'z' }\n\n/**\n * @return whether [this] string contains only digits\n */\nfun String.isDigits(): Boolean = this.all { it.isDigit() }\n\n/**\n * @return whether [this] string contains any uppercase letters\n */\nfun String.hasUppercaseLetter(): Boolean = this.any { it.isUpperCase() }\n\n/**\n * @return whether [this] string contains exactly one or zero letters\n */\n@Suppress(\"FUNCTION_BOOLEAN_PREFIX\")\nfun String.containsOneLetterOrZero(): Boolean {\n    val count = this.count { it.isLetter() }\n    return count == 1 || count == 0\n}\n\n/**\n * method checks that string has prefix like:\n * mFunction, kLength or M_VAR\n *\n * @return true if string has prefix\n */\n@Suppress(\"ForbiddenComment\")\nfun String.hasPrefix(): Boolean {\n    // checking cases like mFunction\n    if (this.isLowerCamelCase() && this.length >= 2 && this.substring(0, 2).count { it in 'A'..'Z' } == 1) {\n        return true\n    }\n    // checking cases like M_VAL\n    if (this.isUpperSnakeCase() && this.length >= 2 && this.substring(0, 2).contains('_')) {\n        return true\n    }\n    return false\n}\n\n/**\n * removing the prefix in the word\n * M_VAR -> VAR\n * mVariable -> variable\n *\n * @return a string without prefix\n */\n@Suppress(\"ForbiddenComment\")\nfun String.removePrefix(): String {\n    // FixMe: there can be cases when after you will change variable name - it becomes a keyword\n    if (this.isLowerCamelCase()) {\n        return this[1].lowercaseChar() + this.substring(2)\n    }\n    if (this.isUpperSnakeCase()) {\n        return this.substring(2)\n    }\n    return this\n}\n\n/**\n * @return the indentation of the last line of this string.\n */\ninternal fun String.lastIndent() = substringAfterLast(NEWLINE).count(::isSpaceCharacter)\n\n/**\n * @return the number of leading space characters in this string.\n */\ninternal fun String.leadingSpaceCount(): Int =\n    asSequence()\n        .takeWhile(::isSpaceCharacter)\n        .count()\n\n/**\n * @param ch the character to examine.\n * @return `true` if [ch] is a [SPACE], `false` otherwise.\n */\nprivate fun isSpaceCharacter(ch: Char): Boolean =\n    ch == SPACE\n"
  },
  {
    "path": "diktat-rules/src/main/kotlin/com/saveourtool/diktat/ruleset/utils/indentation/Checkers.kt",
    "content": "/**\n * Implementations of CustomIndentationChecker for IndentationRule\n */\n\npackage com.saveourtool.diktat.ruleset.utils.indentation\n\nimport com.saveourtool.diktat.ruleset.rules.chapter3.files.IndentationAmount\nimport com.saveourtool.diktat.ruleset.rules.chapter3.files.IndentationAmount.SINGLE\nimport com.saveourtool.diktat.ruleset.rules.chapter3.files.IndentationError\nimport com.saveourtool.diktat.ruleset.utils.hasParent\nimport com.saveourtool.diktat.ruleset.utils.isBooleanExpression\nimport com.saveourtool.diktat.ruleset.utils.isDotBeforeCallOrReference\nimport com.saveourtool.diktat.ruleset.utils.isElvisOperationReference\nimport com.saveourtool.diktat.ruleset.utils.isLongStringTemplateEntry\nimport com.saveourtool.diktat.ruleset.utils.lastIndent\nimport com.saveourtool.diktat.ruleset.utils.nextCodeSibling\nimport com.saveourtool.diktat.ruleset.utils.prevSibling\n\nimport org.jetbrains.kotlin.KtNodeTypes.BINARY_EXPRESSION\nimport org.jetbrains.kotlin.KtNodeTypes.BINARY_WITH_TYPE\nimport org.jetbrains.kotlin.KtNodeTypes.BODY\nimport org.jetbrains.kotlin.KtNodeTypes.DOT_QUALIFIED_EXPRESSION\nimport org.jetbrains.kotlin.KtNodeTypes.ELSE\nimport org.jetbrains.kotlin.KtNodeTypes.IS_EXPRESSION\nimport org.jetbrains.kotlin.KtNodeTypes.LONG_STRING_TEMPLATE_ENTRY\nimport org.jetbrains.kotlin.KtNodeTypes.OPERATION_REFERENCE\nimport org.jetbrains.kotlin.KtNodeTypes.SAFE_ACCESS_EXPRESSION\nimport org.jetbrains.kotlin.KtNodeTypes.SUPER_TYPE_LIST\nimport org.jetbrains.kotlin.KtNodeTypes.THEN\nimport org.jetbrains.kotlin.KtNodeTypes.VALUE_ARGUMENT\nimport org.jetbrains.kotlin.KtNodeTypes.VALUE_ARGUMENT_LIST\nimport org.jetbrains.kotlin.KtNodeTypes.VALUE_PARAMETER\nimport org.jetbrains.kotlin.KtNodeTypes.VALUE_PARAMETER_LIST\nimport org.jetbrains.kotlin.com.intellij.lang.ASTNode\nimport org.jetbrains.kotlin.com.intellij.psi.PsiElement\nimport org.jetbrains.kotlin.com.intellij.psi.PsiWhiteSpace\nimport org.jetbrains.kotlin.kdoc.lexer.KDocTokens\nimport org.jetbrains.kotlin.kdoc.parser.KDocElementTypes\nimport org.jetbrains.kotlin.lexer.KtTokens.ARROW\nimport org.jetbrains.kotlin.lexer.KtTokens.AS_KEYWORD\nimport org.jetbrains.kotlin.lexer.KtTokens.AS_SAFE\nimport org.jetbrains.kotlin.lexer.KtTokens.BLOCK_COMMENT\nimport org.jetbrains.kotlin.lexer.KtTokens.COLON\nimport org.jetbrains.kotlin.lexer.KtTokens.ELVIS\nimport org.jetbrains.kotlin.lexer.KtTokens.EOL_COMMENT\nimport org.jetbrains.kotlin.lexer.KtTokens.EQ\nimport org.jetbrains.kotlin.lexer.KtTokens.LPAR\nimport org.jetbrains.kotlin.lexer.KtTokens.WHITE_SPACE\nimport org.jetbrains.kotlin.psi.KtBlockExpression\nimport org.jetbrains.kotlin.psi.KtFile\nimport org.jetbrains.kotlin.psi.KtIfExpression\nimport org.jetbrains.kotlin.psi.KtLoopExpression\nimport org.jetbrains.kotlin.psi.KtProperty\nimport org.jetbrains.kotlin.psi.KtPropertyAccessor\nimport org.jetbrains.kotlin.psi.KtWhenEntry\nimport org.jetbrains.kotlin.psi.psiUtil.children\nimport org.jetbrains.kotlin.psi.psiUtil.parents\nimport org.jetbrains.kotlin.psi.psiUtil.parentsWithSelf\nimport org.jetbrains.kotlin.psi.psiUtil.siblings\n\n/**\n * Performs the following check: assignment operator increases indent by one step for the expression after it.\n * If [IndentationConfig.extendedIndentForExpressionBodies] is set to `true`, indentation is increased by two steps instead.\n */\ninternal class AssignmentOperatorChecker(configuration: IndentationConfig) : CustomIndentationChecker(configuration) {\n    override fun checkNode(whiteSpace: PsiWhiteSpace, indentError: IndentationError): CheckResult? {\n        whiteSpace.prevSibling?.node?.let { prevNode ->\n            if (prevNode.elementType == EQ && prevNode.treeNext.let { it.elementType == WHITE_SPACE && it.textContains('\\n') }) {\n                return CheckResult.from(indentError.actual, (whiteSpace.parentIndent()\n                    ?: indentError.expected) + IndentationAmount.valueOf(configuration.extendedIndentForExpressionBodies), true)\n            }\n        }\n        return null\n    }\n}\n\n/**\n * Performs the following check: When breaking parameter list of a method/class constructor it can be aligned with 8 spaces\n * or in a method/class declaration a parameter that was moved to a newline can be on the same level as the previous argument.\n */\n@Suppress(\"ForbiddenComment\")\ninternal class ValueParameterListChecker(configuration: IndentationConfig) : CustomIndentationChecker(configuration) {\n    /**\n     * This check triggers if the following conditions are met:\n     * 1. line break is inside value parameter or value argument list (function declaration or invocation)\n     * 2. there are no other line breaks before this node\n     * 3. there are no more arguments after this node\n     */\n    private fun isCheckNeeded(whiteSpace: PsiWhiteSpace) =\n        whiteSpace.parent\n            .node\n            .elementType\n            .let { it == VALUE_PARAMETER_LIST || it == VALUE_ARGUMENT_LIST } &&\n                whiteSpace.siblings(forward = false, withItself = false).none { it is PsiWhiteSpace && it.textContains('\\n') } &&\n                @Suppress(\"PARAMETER_NAME_IN_OUTER_LAMBDA\")\n                // no need to trigger when there are no more parameters in the list\n                whiteSpace.siblings(forward = true, withItself = false).any {\n                    it.node.elementType.run { this == VALUE_ARGUMENT || this == VALUE_PARAMETER }\n                }\n\n    override fun checkNode(whiteSpace: PsiWhiteSpace, indentError: IndentationError): CheckResult? {\n        if (isCheckNeeded(whiteSpace)) {\n            val parameterList = whiteSpace.parent.node\n            // parameters in lambdas are VALUE_PARAMETER_LIST and might have no LPAR: list { elem -> ... }\n            val parameterAfterLpar = parameterList\n                .findChildByType(LPAR)\n                ?.treeNext\n                ?.takeIf {\n                    it.elementType != WHITE_SPACE &&\n                            // there can be multiline arguments and in this case we don't align parameters with them\n                            !it.textContains('\\n')\n                }\n\n            val expectedIndent = if (parameterAfterLpar != null && configuration.alignedParameters && parameterList.elementType == VALUE_PARAMETER_LIST) {\n                val ktFile = whiteSpace.parents.last() as KtFile\n                // count column number of the first parameter\n                ktFile.text\n                    .lineSequence()\n                    // calculate offset for every line end, `+1` for `\\n` which is trimmed in `lineSequence`\n                    .scan(0 to \"\") { (length, _), line -> length + line.length + 1 to line }\n                    .run {\n                        // find the line where `parameterAfterLpar` resides\n                        find { it.first > parameterAfterLpar.startOffset } ?: last()\n                    }\n                    .let { (_, line) -> line.substringBefore(parameterAfterLpar.text).length }\n            } else if (configuration.extendedIndentOfParameters) {\n                indentError.expected + SINGLE\n            } else {\n                indentError.expected\n            }\n\n            return CheckResult.from(indentError.actual, expectedIndent, adjustNext = true, includeLastChild = false)\n        }\n        return null\n    }\n}\n\n/**\n * Performs the following check: When breaking line after operators like +/-/`*` etc. new line can be indented with 8 space\n */\ninternal class ExpressionIndentationChecker(configuration: IndentationConfig) : CustomIndentationChecker(configuration) {\n    override fun checkNode(whiteSpace: PsiWhiteSpace, indentError: IndentationError): CheckResult? =\n        when {\n            whiteSpace.parent.node.elementType in sequenceOf(BINARY_EXPRESSION, BINARY_WITH_TYPE) &&\n                    whiteSpace.immediateSiblings().any { sibling ->\n                        /*\n                         * We're looking for an operation reference, including\n                         * `as` and `as?` (`AS_SAFE`), but excluding `?:` (`ELVIS`),\n                         * because there's a separate flag for Elvis expressions\n                         * in IDEA (`CONTINUATION_INDENT_IN_ELVIS`).\n                         */\n                        sibling.node.elementType == OPERATION_REFERENCE &&\n                                sibling.node.children().firstOrNull()?.elementType != ELVIS\n                    } -> {\n                val parentIndent = whiteSpace.parentIndent() ?: indentError.expected\n                val expectedIndent = parentIndent + IndentationAmount.valueOf(configuration.extendedIndentAfterOperators)\n                CheckResult.from(indentError.actual, expectedIndent, true)\n            }\n\n            else -> null\n        }\n}\n\n/**\n * In KDoc leading asterisks should be indented with one additional space\n */\ninternal class KdocIndentationChecker(config: IndentationConfig) : CustomIndentationChecker(config) {\n    override fun checkNode(whiteSpace: PsiWhiteSpace, indentError: IndentationError): CheckResult? {\n        if (whiteSpace.nextSibling.node.elementType in listOf(KDocTokens.LEADING_ASTERISK, KDocTokens.END, KDocElementTypes.KDOC_SECTION)) {\n            val expectedIndent = indentError.expected + 1\n            return CheckResult.from(indentError.actual, expectedIndent)\n        }\n        return null\n    }\n}\n\n/**\n * This checker indents all super types of class by one INDENT_SIZE or by two if colon is on a new line\n * If class declaration has supertype list, then it should have a colon before it, therefore UnsafeCallOnNullableType inspection is suppressed\n */\n@Suppress(\"UnsafeCallOnNullableType\")\ninternal class SuperTypeListChecker(config: IndentationConfig) : CustomIndentationChecker(config) {\n    override fun checkNode(whiteSpace: PsiWhiteSpace, indentError: IndentationError): CheckResult? {\n        if (whiteSpace.nextSibling.node.elementType == SUPER_TYPE_LIST) {\n            val hasNewlineBeforeColon = whiteSpace.node\n                .prevSibling { it.elementType == COLON }!!\n                .treePrev\n                .takeIf { it.elementType == WHITE_SPACE }\n                ?.textContains('\\n') ?: false\n            val expectedIndent = indentError.expected + IndentationAmount.valueOf(extendedIndent = hasNewlineBeforeColon)\n            return CheckResult.from(indentError.actual, expectedIndent)\n        } else if (whiteSpace.parent.node.elementType == SUPER_TYPE_LIST) {\n            val expectedIndent = whiteSpace.parentIndent() ?: (indentError.expected + SINGLE)\n            return CheckResult.from(indentError.actual, expectedIndent)\n        }\n        return null\n    }\n}\n\n/**\n * This checker performs the following check: When dot call start on a new line, it should be indented by [IndentationConfig.indentationSize].\n * Same is true for safe calls (`?.`) and elvis operator (`?:`).\n */\ninternal class DotCallChecker(config: IndentationConfig) : CustomIndentationChecker(config) {\n    /**\n     * @param nextNodePredicate the predicate which the next non-comment\n     *   non-whitespace node should satisfy.\n     * @return `true` if this is a comment node which is immediately preceding\n     *   the node specified by [nextNodePredicate].\n     */\n    private fun ASTNode.isCommentBefore(nextNodePredicate: ASTNode.() -> Boolean): Boolean {\n        if (elementType in sequenceOf(EOL_COMMENT, BLOCK_COMMENT)) {\n            var nextNode: ASTNode? = treeNext\n            while (nextNode != null && nextNode.elementType in sequenceOf(WHITE_SPACE, EOL_COMMENT)) {\n                nextNode = nextNode.treeNext\n            }\n            return nextNode?.nextNodePredicate() ?: false\n        }\n        return false\n    }\n\n    private fun ASTNode.isElvisReferenceOrCommentBeforeElvis(): Boolean =\n        isElvisOperationReference() ||\n                isCommentBefore(ASTNode::isElvisOperationReference)\n\n    private fun ASTNode.isFromStringTemplate(): Boolean =\n        hasParent(LONG_STRING_TEMPLATE_ENTRY)\n\n    @Suppress(\n        \"ComplexMethod\",\n        \"TOO_LONG_FUNCTION\",\n    )\n    override fun checkNode(whiteSpace: PsiWhiteSpace, indentError: IndentationError): CheckResult? {\n        whiteSpace.nextSibling\n            .node\n            .takeIf { nextNode ->\n                (nextNode.isDotBeforeCallOrReference() ||\n                        nextNode.elementType == OPERATION_REFERENCE &&\n                                nextNode.firstChildNode.elementType in sequenceOf(ELVIS, IS_EXPRESSION, AS_KEYWORD, AS_SAFE) ||\n                        nextNode.isCommentBefore(ASTNode::isDotBeforeCallOrReference) ||\n                        nextNode.isCommentBefore(ASTNode::isElvisOperationReference)) &&\n                        whiteSpace.parents.none(PsiElement::isLongStringTemplateEntry)\n            }\n            /*-\n             * Here, `node` is any of:\n             *\n             *  - a `DOT` or a `SAFE_ACCESS`,\n             *  - an `OPERATION_REFERENCE` with `ELVIS` as the only child, or\n             */\n            ?.let { node ->\n                val indentIncrement = IndentationAmount.valueOf(configuration.extendedIndentBeforeDot)\n                if (node.isFromStringTemplate()) {\n                    return CheckResult.from(indentError.actual, indentError.expected +\n                            indentIncrement, true)\n                }\n\n                /*-\n                 * The list of immediate parents of this whitespace node,\n                 * nearest-to-farthest order\n                 * (the farthest parent is the file node).\n                 */\n                val parentExpressions = whiteSpace.parents.takeWhile { parent ->\n                    val parentType = parent.node.elementType\n\n                    when {\n                        /*\n                         * #1532, 1.2.4+: if this is an Elvis operator\n                         * (OPERATION_REFERENCE -> ELVIS), or an EOL or a\n                         * block comment which immediately precedes this\n                         * Elvis operator, then the indent of the parent\n                         * binary expression should be used as a base for\n                         * the increment.\n                         */\n                        node.isElvisReferenceOrCommentBeforeElvis() -> parentType == BINARY_EXPRESSION\n\n                        /*\n                         * Pre-1.2.4 behaviour, all other cases: the indent\n                         * of the parent dot-qualified or safe-access\n                         * expression should be used as a base for the\n                         * increment.\n                         */\n                        else -> parentType in sequenceOf(\n                            DOT_QUALIFIED_EXPRESSION,\n                            SAFE_ACCESS_EXPRESSION,\n                        )\n                    }\n                }.toList()\n\n                /*\n                 * Selects from the matching parent nodes.\n                 */\n                val matchOrNull: Iterable<PsiElement>.() -> PsiElement? = {\n                    when {\n                        /*\n                         * Selects nearest.\n                         */\n                        node.isElvisReferenceOrCommentBeforeElvis() -> firstOrNull()\n\n                        /*\n                         * Selects farthest.\n                         */\n                        else -> lastOrNull()\n                    }\n                }\n\n                // we need to get indent before the first expression in calls chain\n                /*-\n                 * If the parent indent (the one before a `DOT_QUALIFIED_EXPRESSION`\n                 * or a `SAFE_ACCESS_EXPRESSION`) is `null`, then use 0 as the\n                 * fallback value.\n                 *\n                 * If `indentError.expected` is used as a fallback (pre-1.2.2\n                 * behaviour), this breaks chained dot-qualified or safe-access\n                 * expressions (see #1336), e.g.:\n                 *\n                 * ```kotlin\n                 * val a = first()\n                 *     .second()\n                 *     .third()\n                 * ```\n                 */\n                val parentIndent = (parentExpressions.matchOrNull() ?: whiteSpace).parentIndent()\n                    ?: 0\n\n                val expectedIndent = when {\n                    /*-\n                     * Don't indent Elvis expressions (and the corresponding comments)\n                     * which are nested inside boolean expressions:\n                     *\n                     * ```kotlin\n                     * val x = true &&\n                     *         \"\"\n                     *             ?.isEmpty()\n                     *         ?: true\n                     * ```\n                     *\n                     * This is a special case, and this is how IDEA formats source code.\n                     */\n                    node.isElvisReferenceOrCommentBeforeElvis() &&\n                            parentExpressions.any { it.node.isBooleanExpression() } -> parentIndent\n\n                    /*-\n                     * All other cases (dot-qualified, safe-access, Elvis).\n                     * Expression parts are indented regularly, e.g.:\n                     *\n                     * ```kotlin\n                     * val a = null as Boolean?\n                     *     ?: true\n                     * ```\n                     */\n                    else -> parentIndent + indentIncrement\n                }\n\n                return CheckResult.from(indentError.actual, expectedIndent, true)\n            }\n        return null\n    }\n}\n\n/**\n * This [CustomIndentationChecker] checks indentation in loops and if-else expressions without braces around body.\n */\ninternal class ConditionalsAndLoopsWithoutBracesChecker(config: IndentationConfig) : CustomIndentationChecker(config) {\n    override fun checkNode(whiteSpace: PsiWhiteSpace, indentError: IndentationError): CheckResult? {\n        val parent = whiteSpace.parent\n        val nextNode = whiteSpace.node.nextCodeSibling()  // if there is comment after if or else, it should be indented too\n        return when (parent) {\n            is KtLoopExpression -> nextNode?.elementType == BODY && parent.body !is KtBlockExpression\n            is KtIfExpression -> nextNode?.elementType == THEN && parent.then !is KtBlockExpression ||\n                    nextNode?.elementType == ELSE && parent.`else`.let { it !is KtBlockExpression && it !is KtIfExpression }\n            else -> false\n        }\n            .takeIf { it }\n            ?.let {\n                CheckResult.from(indentError.actual, indentError.expected + SINGLE, true)\n            }\n    }\n}\n\n/**\n * This [CustomIndentationChecker] check indentation before custom getters and setters on property.\n */\ninternal class CustomGettersAndSettersChecker(config: IndentationConfig) : CustomIndentationChecker(config) {\n    override fun checkNode(whiteSpace: PsiWhiteSpace, indentError: IndentationError): CheckResult? {\n        val parent = whiteSpace.parent\n        if (parent is KtProperty && whiteSpace.nextSibling is KtPropertyAccessor) {\n            return CheckResult.from(indentError.actual, (parent.parentIndent()\n                ?: indentError.expected) + SINGLE, true)\n        }\n        return null\n    }\n}\n\n/**\n * Performs the following check: arrow in `when` expression increases indent by one step for the expression after it.\n */\ninternal class ArrowInWhenChecker(configuration: IndentationConfig) : CustomIndentationChecker(configuration) {\n    override fun checkNode(whiteSpace: PsiWhiteSpace, indentError: IndentationError): CheckResult? {\n        val prevNode = whiteSpace.prevSibling?.node\n        if (prevNode?.elementType == ARROW && whiteSpace.parent is KtWhenEntry) {\n            return CheckResult.from(indentError.actual, (whiteSpace.parentIndent()\n                ?: indentError.expected) + SINGLE, true)\n        }\n        return null\n    }\n}\n\n/**\n * @return indentation of parent node\n */\ninternal fun PsiElement.parentIndent(): Int? = parentsWithSelf\n    .map { parent ->\n        parent.node.prevSibling { it.elementType == WHITE_SPACE && it.textContains('\\n') }\n    }\n    .filterNotNull()\n    .firstOrNull()\n    ?.text\n    ?.lastIndent()\n\n/**\n * @return the sequence of immediate siblings (the previous and the next one),\n *   excluding `null`'s.\n */\nprivate fun PsiElement.immediateSiblings(): Sequence<PsiElement> =\n    sequenceOf(prevSibling, nextSibling).filterNotNull()\n"
  },
  {
    "path": "diktat-rules/src/main/kotlin/com/saveourtool/diktat/ruleset/utils/indentation/CustomIndentationChecker.kt",
    "content": "/**\n * Utility classes for IndentationRule\n */\n\npackage com.saveourtool.diktat.ruleset.utils.indentation\n\nimport com.saveourtool.diktat.ruleset.rules.chapter3.files.IndentationConfigAware\nimport com.saveourtool.diktat.ruleset.rules.chapter3.files.IndentationError\nimport com.saveourtool.diktat.ruleset.utils.NEWLINE\n\nimport org.jetbrains.kotlin.com.intellij.psi.PsiWhiteSpace\n\n/**\n * @property configuration configuration of indentation rule\n */\ninternal abstract class CustomIndentationChecker(override val configuration: IndentationConfig) : IndentationConfigAware {\n    /**\n     * This method checks if this white space is an exception from general rule\n     * If true, checks if it is properly indented and fixes\n     *\n     * @param whiteSpace PSI element of type [PsiWhiteSpace]. The whitespace is\n     *   guaranteed to contain a [newline][NEWLINE].\n     * @param indentError and [IndentationError] on this node\n     * @return null true if node is not an exception, CheckResult otherwise\n     */\n    abstract fun checkNode(whiteSpace: PsiWhiteSpace, indentError: IndentationError): CheckResult?\n}\n\n/**\n * @property adjustNext Indicates whether the indent returned by this exception checker needs to be applied to other nodes with same parent\n * @property includeLastChild Indicates whether the white space before the last child node of the initiator node should have increased indent or not\n * @property isCorrect whether indentation check is correct\n * @property expectedIndent expected indentation\n */\ninternal data class CheckResult(\n    val isCorrect: Boolean,\n    val expectedIndent: Int,\n    val adjustNext: Boolean,\n    val includeLastChild: Boolean = true\n) {\n    companion object {\n        /**\n         * @param actual actual indentation\n         * @param expected expected indentation\n         * @param adjustNext see [CheckResult.adjustNext]\n         * @param includeLastChild see [CheckResult.includeLastChild]\n         * @return an instance of [CheckResult]\n         */\n        fun from(actual: Int,\n                 expected: Int,\n                 adjustNext: Boolean = false,\n                 includeLastChild: Boolean = true\n        ) = CheckResult(actual == expected, expected, adjustNext, includeLastChild)\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/main/kotlin/com/saveourtool/diktat/ruleset/utils/indentation/IndentationConfig.kt",
    "content": "package com.saveourtool.diktat.ruleset.utils.indentation\n\nimport com.saveourtool.diktat.api.DiktatErrorEmitter\nimport com.saveourtool.diktat.common.config.rules.RuleConfiguration\n\n/**\n * [RuleConfiguration] for indentation logic\n */\nclass IndentationConfig(config: Map<String, String>) : RuleConfiguration(config) {\n    /**\n     * Is newline at the end of a file needed\n     */\n    val newlineAtEnd = config[NEWLINE_AT_END]?.toBoolean() ?: true\n\n    /**\n     * If true, in parameter list when parameters are split by newline they are indented with two indentations instead of one\n     */\n    val extendedIndentOfParameters = config[EXTENDED_INDENT_OF_PARAMETERS]?.toBoolean() ?: false\n\n    /**\n     * If true, if first parameter in parameter list is on the same line as opening parenthesis, then other parameters\n     * can be aligned with it\n     */\n    val alignedParameters = config[ALIGNED_PARAMETERS]?.toBoolean() ?: true\n\n    /**\n     * If `true`, expression bodies which begin on a separate line are indented\n     * using a _continuation indent_. The flag is **off**:\n     *\n     * ```kotlin\n     * val a: Boolean =\n     *     false\n     *\n     * val b: Boolean\n     *     get() =\n     *         false\n     *\n     * fun f(): Boolean =\n     *     false\n     * ```\n     *\n     *  The flag is **on**:\n     *\n     * ```kotlin\n     * val a: Boolean =\n     *         false\n     *\n     * val b: Boolean\n     *     get() =\n     *             false\n     *\n     * fun f(): Boolean =\n     *         false\n     * ```\n     *\n     * The default is `false`.\n     *\n     * This flag is called `CONTINUATION_INDENT_FOR_EXPRESSION_BODIES` in _IDEA_\n     * and `ij_kotlin_continuation_indent_for_expression_bodies` in\n     * `.editorconfig`.\n     *\n     * @since 1.2.2\n     */\n    val extendedIndentForExpressionBodies = config[EXTENDED_INDENT_FOR_EXPRESSION_BODIES]?.toBoolean() ?: false\n\n    /**\n     * If true, if expression is split by newline after operator like +/-/`*`, then the next line is indented with two indentations instead of one\n     */\n    val extendedIndentAfterOperators = config[EXTENDED_INDENT_AFTER_OPERATORS]?.toBoolean() ?: true\n\n    /**\n     * If true, when dot qualified expression starts on a new line, this line will be indented with\n     * two indentations instead of one\n     */\n    val extendedIndentBeforeDot = config[EXTENDED_INDENT_BEFORE_DOT]?.toBoolean() ?: false\n\n    /**\n     * The indentation size for each file\n     */\n    val indentationSize = config[INDENTATION_SIZE]?.toInt() ?: DEFAULT_INDENTATION_SIZE\n\n    override fun equals(other: Any?): Boolean =\n        other is IndentationConfig && configWithExplicitDefaults == other.configWithExplicitDefaults\n\n    override fun hashCode(): Int =\n        configWithExplicitDefaults.hashCode()\n\n    override fun toString(): String =\n        \"${javaClass.simpleName}$configWithExplicitDefaults\"\n\n    /**\n     * @param errorEmitter\n     * @return overridden [errorEmitter] which warns message with configured [indentationSize]\n     */\n    fun overrideIfRequiredWarnMessage(errorEmitter: DiktatErrorEmitter): DiktatErrorEmitter = if (indentationSize == DEFAULT_INDENTATION_SIZE) {\n        errorEmitter\n    } else {\n        DiktatErrorEmitter { offset, errorMessage, canBeAutoCorrected ->\n            errorEmitter(offset, errorMessage.replace(\"should equal to 4 spaces (tabs are not allowed)\", \"should equal to $indentationSize spaces (tabs are not allowed)\"),\n                canBeAutoCorrected)\n        }\n    }\n\n    companion object {\n        internal const val ALIGNED_PARAMETERS = \"alignedParameters\"\n\n        /**\n         * The default indent size (space characters), configurable via\n         * `indentationSize`.\n         */\n        private const val DEFAULT_INDENTATION_SIZE = 4\n        const val EXTENDED_INDENT_AFTER_OPERATORS = \"extendedIndentAfterOperators\"\n        const val EXTENDED_INDENT_BEFORE_DOT = \"extendedIndentBeforeDot\"\n        const val EXTENDED_INDENT_FOR_EXPRESSION_BODIES = \"extendedIndentForExpressionBodies\"\n        const val EXTENDED_INDENT_OF_PARAMETERS = \"extendedIndentOfParameters\"\n        const val INDENTATION_SIZE = \"indentationSize\"\n        const val NEWLINE_AT_END = \"newlineAtEnd\"\n\n        @Suppress(\"CUSTOM_GETTERS_SETTERS\")\n        private val IndentationConfig.configWithExplicitDefaults: Map<String, String>\n            get() =\n                mutableMapOf<String, Any>().apply {\n                    putAll(config)\n                    putIfAbsent(ALIGNED_PARAMETERS, alignedParameters)\n                    putIfAbsent(EXTENDED_INDENT_AFTER_OPERATORS, extendedIndentAfterOperators)\n                    putIfAbsent(EXTENDED_INDENT_BEFORE_DOT, extendedIndentBeforeDot)\n                    putIfAbsent(EXTENDED_INDENT_FOR_EXPRESSION_BODIES, extendedIndentForExpressionBodies)\n                    putIfAbsent(EXTENDED_INDENT_OF_PARAMETERS, extendedIndentOfParameters)\n                    putIfAbsent(INDENTATION_SIZE, indentationSize)\n                    putIfAbsent(NEWLINE_AT_END, newlineAtEnd)\n                }.mapValues { (_, value) ->\n                    value.toString()\n                }\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/main/kotlin/com/saveourtool/diktat/ruleset/utils/search/VariablesSearch.kt",
    "content": "@file:Suppress(\n    \"KDOC_NO_CONSTRUCTOR_PROPERTY\",\n    \"MISSING_KDOC_CLASS_ELEMENTS\",\n    \"MISSING_KDOC_ON_FUNCTION\",\n    \"KDOC_WITHOUT_PARAM_TAG\",\n    \"KDOC_WITHOUT_RETURN_TAG\"\n)\n\npackage com.saveourtool.diktat.ruleset.utils.search\n\nimport com.saveourtool.diktat.ruleset.utils.findAllDescendantsWithSpecificType\nimport com.saveourtool.diktat.ruleset.utils.getDeclarationScope\nimport com.saveourtool.diktat.ruleset.utils.isGoingAfter\n\nimport org.jetbrains.kotlin.KtNodeTypes\nimport org.jetbrains.kotlin.com.intellij.lang.ASTNode\nimport org.jetbrains.kotlin.psi.KtBlockExpression\nimport org.jetbrains.kotlin.psi.KtClassBody\nimport org.jetbrains.kotlin.psi.KtDotQualifiedExpression\nimport org.jetbrains.kotlin.psi.KtElement\nimport org.jetbrains.kotlin.psi.KtFile\nimport org.jetbrains.kotlin.psi.KtFunctionLiteral\nimport org.jetbrains.kotlin.psi.KtNameReferenceExpression\nimport org.jetbrains.kotlin.psi.KtProperty\nimport org.jetbrains.kotlin.psi.psiUtil.getChildrenOfType\nimport org.jetbrains.kotlin.psi.psiUtil.getParentOfType\nimport org.jetbrains.kotlin.psi.psiUtil.parents\nimport org.jetbrains.kotlin.psi.psiUtil.referenceExpression\nimport org.jetbrains.kotlin.psi.stubs.elements.KtFileElementType\n\n/**\n *  @param node root node of a type File that is used to search all declared properties (variables)\n *  it should be ONLY node of File elementType\n *  @param filterForVariables condition to filter\n */\nabstract class VariablesSearch(val node: ASTNode,\n                               private val filterForVariables: (KtProperty) -> Boolean) {\n    /**\n     * to complete implementation of a search mechanism you need to specify what and how you will search in current scope\n     * [this] - scope where to search the usages/assignments/e.t.c of the variable (can be of types KtBlockExpression/KtFile/KtClassBody)\n     */\n    protected abstract fun KtElement.getAllSearchResults(property: KtProperty): List<KtNameReferenceExpression>\n\n    /**\n     * method collects all declared variables and it's usages\n     *\n     * @return a map of a property to it's usages\n     */\n    @Suppress(\"TYPE_ALIAS\")\n    fun collectVariables(): Map<KtProperty, List<KtNameReferenceExpression>> {\n        require(node.elementType == KtFileElementType.INSTANCE) {\n            \"To collect all variables in a file you need to provide file root node\"\n        }\n        return node\n            .findAllDescendantsWithSpecificType(KtNodeTypes.PROPERTY)\n            .map { it.psi as KtProperty }\n            .filter(filterForVariables)\n            .associateWith { it.getSearchResults() }\n    }\n\n    @Suppress(\"UnsafeCallOnNullableType\")\n    fun KtProperty.getSearchResults() = this\n        .getDeclarationScope()\n        // if declaration scope is not null - then we have found out the block where this variable is stored\n        // else - it is a global variable on a file level or a property on the class level\n        .let { declarationScope ->\n            // searching in the scope with declaration (in the context)\n            declarationScope?.getAllSearchResults(this)\n                // searching on the class level in class body\n                ?: (this.getParentOfType<KtClassBody>(true)?.getAllSearchResults(this))\n                // searching on the file level\n                ?: (this.getParentOfType<KtFile>(true)!!.getAllSearchResults(this))\n        }\n\n    /**\n     * filtering object's fields (expressions) that have same name as variable\n     */\n    protected fun KtNameReferenceExpression.isReferenceToFieldOfObject(): Boolean {\n        val expression = this\n        return (expression.parent as? KtDotQualifiedExpression)?.run {\n            receiverExpression != expression && selectorExpression?.referenceExpression() == expression\n        } ?: false\n    }\n\n    /**\n     * filtering local properties from other context (shadowed) and lambda and function arguments with same name\n     *  going through all parent scopes from bottom to top until we will find the scope where the initial variable was declared\n     *  all these scopes are on lower level of inheritance that's why if in one of these scopes we will find any\n     *  variable declaration with the same name - we will understand that it is usage of another variable\n     */\n    protected fun isReferenceToOtherVariableWithSameName(expression: KtNameReferenceExpression,\n                                                         codeBlock: KtElement,\n                                                         property: KtProperty\n    ) = expression.parents\n        // getting all block expressions/class bodies/file node from bottom to the top\n        // FixMe: Object companion is not resolved properly yet\n        .filter { it is KtBlockExpression || it is KtClassBody || it is KtFile }\n        // until we reached the block that contains the initial declaration\n        .takeWhile { codeBlock != it }\n        .any { block ->\n            // this is not the expression that we needed if:\n            // 1) there is a new shadowed declaration for this expression (but the declaration should stay on the previous line!)\n            // 2) or there one of top blocks is a function/lambda that has arguments with the same name\n            // FixMe: in class or a file the declaration can easily go after the usage (by lines of code)\n            block.getChildrenOfType<KtProperty>()\n                .any { it.nameAsName == property.nameAsName && expression.node.isGoingAfter(it.node) } ||\n                    block.parent\n                        .let { it as? KtFunctionLiteral }\n                        ?.valueParameters\n                        ?.any { it.nameAsName == property.nameAsName }\n                    ?: false\n            // FixMe: also see very strange behavior of Kotlin in tests (disabled)\n        }\n}\n\n/**\n * this is a small workaround in case we don't want to make any custom filter while searching variables\n *\n * @param node an [ASTNode]\n */\n@Suppress(\"UNUSED_PARAMETER\", \"FunctionOnlyReturningConstant\")\nfun default(node: KtProperty) = true\n"
  },
  {
    "path": "diktat-rules/src/main/kotlin/com/saveourtool/diktat/ruleset/utils/search/VariablesWithAssignmentSearch.kt",
    "content": "@file:Suppress(\n    \"MISSING_KDOC_TOP_LEVEL\",\n    \"KDOC_NO_CONSTRUCTOR_PROPERTY\",\n    \"MISSING_KDOC_CLASS_ELEMENTS\",\n    \"MISSING_KDOC_ON_FUNCTION\",\n    \"KDOC_WITHOUT_PARAM_TAG\",\n    \"KDOC_WITHOUT_RETURN_TAG\",\n    \"KDOC_NO_EMPTY_TAGS\"\n)\n\npackage com.saveourtool.diktat.ruleset.utils.search\n\nimport com.saveourtool.diktat.ruleset.utils.findAllDescendantsWithSpecificType\nimport com.saveourtool.diktat.ruleset.utils.isGoingAfter\n\nimport org.jetbrains.kotlin.KtNodeTypes\nimport org.jetbrains.kotlin.com.intellij.lang.ASTNode\nimport org.jetbrains.kotlin.lexer.KtTokens\nimport org.jetbrains.kotlin.psi.KtBinaryExpression\nimport org.jetbrains.kotlin.psi.KtElement\nimport org.jetbrains.kotlin.psi.KtNameReferenceExpression\nimport org.jetbrains.kotlin.psi.KtProperty\n\nclass VariablesWithAssignmentSearch(fileNode: ASTNode,\n                                    filterForVariables: (KtProperty) -> Boolean) : VariablesSearch(fileNode, filterForVariables) {\n    /**\n     * searching for all assignments of variables in current context [this]\n     *\n     * @param property\n     * @return\n     */\n    override fun KtElement.getAllSearchResults(property: KtProperty) = this.node\n        .findAllDescendantsWithSpecificType(KtNodeTypes.BINARY_EXPRESSION)\n        // filtering out all usages that are declared in the same context but are going before the variable declaration\n        // AND checking that there is an assignment\n        .filter {\n            // FixMe: bug is here with a search of postfix/prefix variables assignment (like ++).\n            // FixMe: Currently we check only val a = 5, ++a is not checked here\n            // FixMe: also there can be some tricky cases with setters, but I am not able to imagine them now\n            it.isGoingAfter(property.node) &&\n                    (it.psi as KtBinaryExpression).operationToken == KtTokens.EQ &&\n                    (it.psi as KtBinaryExpression)\n                        .left\n                        ?.node\n                        ?.elementType == KtNodeTypes.REFERENCE_EXPRESSION\n        }\n        .map { (it.psi as KtBinaryExpression).left as KtNameReferenceExpression }\n        // checking that name of the property in usage matches with the name in the declaration\n        .filter { it.getReferencedNameAsName() == property.nameAsName }\n        .filterNot { expression ->\n            // to avoid false triggering on objects' fields with same name as property\n            expression.isReferenceToFieldOfObject() ||\n                    // to exclude usages of local properties from other context (shadowed) and lambda arguments with same name\n                    isReferenceToOtherVariableWithSameName(expression, this, property)\n        }\n        .toList()\n}\n\n/**\n * the default value for filtering condition is always true\n */\nfun ASTNode.findAllVariablesWithAssignments(filterForVariables: (KtProperty) -> Boolean = ::default) =\n    VariablesWithAssignmentSearch(this, filterForVariables).collectVariables()\n"
  },
  {
    "path": "diktat-rules/src/main/kotlin/com/saveourtool/diktat/ruleset/utils/search/VariablesWithUsagesSearch.kt",
    "content": "@file:Suppress(\n    \"MISSING_KDOC_TOP_LEVEL\",\n    \"KDOC_NO_CONSTRUCTOR_PROPERTY\",\n    \"MISSING_KDOC_CLASS_ELEMENTS\",\n    \"MISSING_KDOC_ON_FUNCTION\",\n    \"KDOC_WITHOUT_PARAM_TAG\",\n    \"KDOC_WITHOUT_RETURN_TAG\",\n    \"KDOC_NO_EMPTY_TAGS\"\n)\n\npackage com.saveourtool.diktat.ruleset.utils.search\n\nimport com.saveourtool.diktat.ruleset.utils.findAllDescendantsWithSpecificType\nimport com.saveourtool.diktat.ruleset.utils.isGoingAfter\n\nimport org.jetbrains.kotlin.KtNodeTypes\nimport org.jetbrains.kotlin.com.intellij.lang.ASTNode\nimport org.jetbrains.kotlin.psi.KtElement\nimport org.jetbrains.kotlin.psi.KtNameReferenceExpression\nimport org.jetbrains.kotlin.psi.KtProperty\n\nclass VariablesWithUsagesSearch(fileNode: ASTNode,\n                                filterForVariables: (KtProperty) -> Boolean) : VariablesSearch(fileNode, filterForVariables) {\n    override fun KtElement.getAllSearchResults(property: KtProperty) = this.node\n        .findAllDescendantsWithSpecificType(KtNodeTypes.REFERENCE_EXPRESSION)\n        // filtering out all usages that are declared in the same context but are going before the variable declaration\n        .filter { it.isGoingAfter(property.node) }\n        .map { it.psi as KtNameReferenceExpression }\n        .filter { it.getReferencedNameAsName() == property.nameAsName }\n        .filterNot { expression ->\n            // to avoid false triggering on objects' fields with same name as property\n            expression.isReferenceToFieldOfObject() ||\n                    // to exclude usages of local properties from other context (shadowed) and lambda arguments with same name\n                    isReferenceToOtherVariableWithSameName(expression, this, property)\n        }\n}\n\n/**\n * the default value for filtering condition is always true\n */\nfun ASTNode.findAllVariablesWithUsages(filterForVariables: (KtProperty) -> Boolean = ::default) =\n    VariablesWithUsagesSearch(this, filterForVariables).collectVariables()\n"
  },
  {
    "path": "diktat-rules/src/main/resources/diktat-analysis-huawei.yml",
    "content": "# Common configuration\n- name: DIKTAT_COMMON\n  enabled: true\n  configuration:\n    # put your package name here - it will be autofixed and checked\n    domainName: com.huawei\n    # testDirs: test\n    disabledChapters: \"\"\n    testDirs: test\n    kotlinVersion: 2.1\n    srcDirectories: \"main\"\n# Checks that the Class/Enum/Interface name matches Pascal case\n- name: CLASS_NAME_INCORRECT\n  enabled: true\n  # all code blocks with MyAnnotation will be ignored and not checked\n  ignoreAnnotated: [ MyAnnotation ]\n# Checks that CONSTANT (treated as const val from companion object or class level) is in non UPPER_SNAKE_CASE\n- name: CONSTANT_UPPERCASE\n  enabled: true\n# Checks that enum value is in upper SNAKE_CASE or in PascalCase depending on the config. UPPER_SNAKE_CASE is the default, but can be changed by 'enumStyle' config\n- name: ENUM_VALUE\n  enabled: true\n  configuration:\n    # Two options: SNAKE_CASE (default), PascalCase\n    enumStyle: SNAKE_CASE\n# Checks that class which extends any Exception class has Exception suffix\n- name: EXCEPTION_SUFFIX\n  enabled: true\n# Checks that file name has extension\n- name: FILE_NAME_INCORRECT\n  enabled: true\n# Checks that file name matches class name, if it is only one class in file\n- name: FILE_NAME_MATCH_CLASS\n  enabled: true\n# Checks that functions/methods which return boolean have special prefix like \"is/should/e.t.c\"\n- name: FUNCTION_BOOLEAN_PREFIX\n  enabled: true\n  configuration:\n    allowedPrefixes: \"\" # A list of functions that return boolean and are allowed to use. Input is in a form \"foo, bar\".\n# Checks that function/method name is in lowerCamelCase\n- name: FUNCTION_NAME_INCORRECT_CASE\n  enabled: true\n# Checks that typealias name is in PascalCase\n- name: TYPEALIAS_NAME_INCORRECT_CASE\n  enabled: true\n# Checks that generic name doesn't contain more than 1 letter (capital). It can be followed by numbers, example: T12, T\n- name: GENERIC_NAME\n  enabled: true\n# Identifier length should be in range [2,64] except names that used in industry like {i, j} and 'e' for catching exceptions\n- name: IDENTIFIER_LENGTH\n  enabled: true\n# Checks that the object matches PascalCase\n- name: OBJECT_NAME_INCORRECT\n  enabled: true\n# Checks that package name is in correct (lower) case\n- name: PACKAGE_NAME_INCORRECT_CASE\n  enabled: true\n# Checks that package name starts with the company's domain\n- name: PACKAGE_NAME_INCORRECT_PREFIX\n  enabled: true\n# Checks that package name does not have incorrect symbols like underscore or non-ASCII letters/digits\n- name: PACKAGE_NAME_INCORRECT_SYMBOLS\n  enabled: true\n# Checks that the path for a file matches with a package name\n- name: PACKAGE_NAME_INCORRECT_PATH\n  enabled: true\n# Checks that package name is in the file\n- name: PACKAGE_NAME_MISSING\n  enabled: true\n# Checks that variable does not have prefix (like mVariable or M_VARIABLE)\n- name: VARIABLE_HAS_PREFIX\n  enabled: true\n# Checks that variable does not contain one single letter, only exceptions are fixed names that used in industry like {i, j}\n- name: VARIABLE_NAME_INCORRECT\n  enabled: true\n# Checks that the name of variable is in lowerCamelCase and contains only ASCII letters\n- name: VARIABLE_NAME_INCORRECT_FORMAT\n  enabled: true\n# Checks that functions have kdoc\n- name: MISSING_KDOC_ON_FUNCTION\n  enabled: true\n# Checks that on file level internal or public class or function has missing KDoc\n- name: MISSING_KDOC_TOP_LEVEL\n  enabled: true\n# Checks that accessible internal elements (protected, public, internal) in a class are documented\n- name: MISSING_KDOC_CLASS_ELEMENTS\n  enabled: true\n# Checks that accessible method parameters are documented in KDoc\n- name: KDOC_WITHOUT_PARAM_TAG\n  enabled: true\n# Checks that accessible method explicit return type is documented in KDoc\n- name: KDOC_WITHOUT_RETURN_TAG\n  enabled: true\n# Checks that accessible method throw keyword is documented in KDoc\n- name: KDOC_WITHOUT_THROWS_TAG\n  enabled: true\n# Checks that KDoc is not empty\n- name: KDOC_EMPTY_KDOC\n  enabled: true\n# Checks that underscore is correctly used to split package naming\n- name: INCORRECT_PACKAGE_SEPARATOR\n  enabled: true\n# Checks that code block doesn't contain kdoc comments\n- name: COMMENTED_BY_KDOC\n  enabled: true\n# Checks that there is no @deprecated tag in kdoc\n- name: KDOC_NO_DEPRECATED_TAG\n  enabled: true\n# Checks that there is no empty content in kdoc tags\n- name: KDOC_NO_EMPTY_TAGS\n  enabled: true\n# Checks that there is only one space after kdoc tag\n- name: KDOC_WRONG_SPACES_AFTER_TAG\n  enabled: true\n# Checks tags order in kDoc. `@param`, `@return`, `@throws`\n- name: KDOC_WRONG_TAGS_ORDER\n  enabled: true\n# Checks that there is no newline of empty KDoc line (with leading asterisk) between `@param`, `@return`, `@throws` tags\n- name: KDOC_NO_NEWLINES_BETWEEN_BASIC_TAGS\n  enabled: true\n# Checks that block of tags @param, @return, @throws is separated from previous part of KDoc by exactly one empty line\n- name: KDOC_NEWLINES_BEFORE_BASIC_TAGS\n  enabled: true\n# Checks that special tags `@apiNote`, `@implNote`, `@implSpec` have exactly one empty line after\n- name: KDOC_NO_NEWLINE_AFTER_SPECIAL_TAGS\n  enabled: true\n# Checks that kdoc does not contain @author tag or date\n- name: KDOC_CONTAINS_DATE_OR_AUTHOR\n  enabled: true\n  configuration:\n    versionRegex: \\d+\\.\\d+\\.\\d+[-.\\w\\d]*\n# Checks that KDoc does not contain single line with words 'return', 'get' or 'set'\n- name: KDOC_TRIVIAL_KDOC_ON_FUNCTION\n  enabled: true\n# Checks that there is newline after header KDoc\n- name: HEADER_WRONG_FORMAT\n  enabled: true\n# Checks that file with zero or >1 classes has header KDoc\n- name: HEADER_MISSING_IN_NON_SINGLE_CLASS_FILE\n  enabled: true\n# Checks that copyright exists on top of file and is properly formatted (as a block comment)\n- name: HEADER_MISSING_OR_WRONG_COPYRIGHT\n  enabled: true\n  configuration:\n    isCopyrightMandatory: true\n    copyrightText: ' Copyright (c) Huawei Technologies Co., Ltd. 2012-;@currYear;. All rights reserved.'\n# Checks that header kdoc is located before package directive\n- name: HEADER_NOT_BEFORE_PACKAGE\n  enabled: true\n# Checks that file does not contain lines > maxSize\n- name: FILE_IS_TOO_LONG\n  enabled: true\n  configuration:\n    # number of lines\n    maxSize: '2000'\n# Checks that file does not contain commented out code\n- name: COMMENTED_OUT_CODE\n  enabled: true\n# Checks that file does not contain only comments, imports and package directive\n- name: FILE_CONTAINS_ONLY_COMMENTS\n  enabled: true\n# Orders imports alphabetically\n- name: FILE_UNORDERED_IMPORTS\n  enabled: true\n  configuration:\n    # use logical imports grouping with sorting inside of a group\n    useRecommendedImportsOrder: true\n# Checks that general order of code parts is right\n- name: FILE_INCORRECT_BLOCKS_ORDER\n  enabled: true\n# Checks that there is exactly one line between code blocks\n- name: FILE_NO_BLANK_LINE_BETWEEN_BLOCKS\n  enabled: true\n# Checks that there is no wildcard imports. Exception: allowedWildcards\n- name: FILE_WILDCARD_IMPORTS\n  enabled: true\n  configuration:\n    allowedWildcards: \"\" # Allowed wildcards for imports (e.g. \"import com.saveourtool.diktat.*, import org.jetbrains.kotlin.*\")\n    useRecommendedImportsOrder: true\n# Checks unused imports\n- name: UNUSED_IMPORT\n  enabled: true\n  configuration:\n    deleteUnusedImport: true\n# Checks that braces are used in if, else, when, for, do, and while statements. Exception: single line ternary operator statement\n- name: NO_BRACES_IN_CONDITIONALS_AND_LOOPS\n  enabled: true\n# Checks that the declaration part of a class-like code structures (class/interface/etc.) is in the proper order\n- name: WRONG_ORDER_IN_CLASS_LIKE_STRUCTURES\n  enabled: true\n# Checks that properties with comments are separated by a blank line\n- name: BLANK_LINE_BETWEEN_PROPERTIES\n  enabled: true\n# Checks top level order\n- name: TOP_LEVEL_ORDER\n  enabled: true\n# Checks that non-empty code blocks with braces follow the K&R style (1TBS or OTBS style)\n- name: BRACES_BLOCK_STRUCTURE_ERROR\n  enabled: true\n  configuration:\n    openBraceNewline: 'True'\n    closeBraceNewline: 'True'\n# Checks that indentation is correct\n- name: WRONG_INDENTATION\n  enabled: true\n  configuration:\n    # Is newline at the end of a file needed\n    newlineAtEnd: true\n    # If true: in parameter list when parameters are split by newline they are indented with two indentations instead of one\n    extendedIndentOfParameters: false\n    # If true: if first parameter in parameter list is on the same line as opening parenthesis, then other parameters can be aligned with it\n    alignedParameters: true\n    # If true, expression bodies which begin on a separate line are indented\n    # using a continuation indent. The default is false.\n    #\n    # This flag is called CONTINUATION_INDENT_FOR_EXPRESSION_BODIES in IDEA and\n    # ij_kotlin_continuation_indent_for_expression_bodies in .editorconfig.\n    extendedIndentForExpressionBodies: false\n    # If true: if expression is split by newline after operator like +/-/`*`, then the next line is indented with two indentations instead of one\n    extendedIndentAfterOperators: true\n    # If true: when dot qualified expression starts on a new line, this line will be indented with two indentations instead of one\n    extendedIndentBeforeDot: false\n    # The indentation size for each file\n    indentationSize: 4\n# Checks that there is no empty blocks in a file.\n# If allowEmptyBlocks is true, checks that it follows correct style (have a newline)\n- name: EMPTY_BLOCK_STRUCTURE_ERROR\n  enabled: true\n  configuration:\n    # Whether a newline after `{` is required in an empty block\n    styleEmptyBlockWithNewline: 'True'\n    allowEmptyBlocks: 'False'\n# Checks that there is no more than one statement per line\n- name: MORE_THAN_ONE_STATEMENT_PER_LINE\n  enabled: true\n# Checks that the line length is < lineLength parameter\n- name: LONG_LINE\n  enabled: true\n  configuration:\n    lineLength: '120'\n# Checks that semicolons are not used at the end of a line\n- name: REDUNDANT_SEMICOLON\n  enabled: true\n# Checks that line breaks follow code style guide: rule 3.6\n- name: WRONG_NEWLINES\n  enabled: true\n  configuration:\n    # If the number of parameters on one line is more than this threshold, all parameters will be placed on separate lines.\n    maxParametersInOneLine: 2\n    # 3 by default.\n    maxCallsInOneLine: 3\n# Checks trailing comma\n- name: TRAILING_COMMA\n  enabled: true\n  configuration:\n    # VALUE_ARGUMENT\n    valueArgument: false\n    # VALUE_PARAMETER\n    valueParameter: false\n    # REFERENCE_EXPRESSION\n    indices: false\n    # WHEN_CONDITION_WITH_EXPRESSION\n    whenConditions: false\n    # STRING_TEMPLATE\n    collectionLiteral: false\n    # TYPE_PROJECTION\n    typeArgument: false\n    # TYPE_PARAMETER\n    typeParameter: false\n    # DESTRUCTURING_DECLARATION_ENTRY\n    destructuringDeclaration: false\n# Checks that there are not too many consecutive spaces in line\n- name: TOO_MANY_CONSECUTIVE_SPACES\n  enabled: true\n  configuration:\n    # Maximum allowed number of consecutive spaces (not counting indentation)\n    maxSpaces: '1'\n    # Whether formatting for enums should be kept without checking\n    saveInitialFormattingForEnums: false\n# Inspection that checks if a long dot qualified expression is used in condition or as an argument\n- name: COMPLEX_EXPRESSION\n  enabled: true\n# Checks that blank lines are used correctly.\n# For example: triggers when there are too many blank lines between function declaration\n- name: TOO_MANY_BLANK_LINES\n  enabled: true\n# Checks that usage of horizontal spaces doesn't violate code style guide\n- name: WRONG_WHITESPACE\n  enabled: true\n# Checks that backticks (``) are not used in the identifier name, except the case when it is test method (marked with @Test annotation)\n- name: BACKTICKS_PROHIBITED\n  enabled: true\n# Checks that a single line concatenation of strings is not used\n- name: STRING_CONCATENATION\n  enabled: true\n# Checks that each when statement have else in the end\n- name: WHEN_WITHOUT_ELSE\n  enabled: true\n# Checks that annotation is on a single line\n- name: ANNOTATION_NEW_LINE\n  enabled: true\n# Checks that method annotated with `Preview` annotation is private and has Preview suffix\n- name: PREVIEW_ANNOTATION\n  enabled: true\n# Checks that enum structure is correct: enum entries should be separated by comma and line break and last entry should have semicolon in the end.\n- name: ENUMS_SEPARATED\n  enabled: true\n# Checks that value on integer or float constant is not too big\n- name: LONG_NUMERICAL_VALUES_SEPARATED\n  enabled: true\n  configuration:\n    # Maximum number of digits which are not split\n    maxNumberLength: '5'\n    # Maximum number of digits between separators\n    maxBlockLength: '3'\n# Checks magic number\n- name: MAGIC_NUMBER\n  enabled: true\n  configuration:\n    # Ignore numbers from test\n    ignoreTest: \"true\"\n    # Ignore numbers\n    ignoreNumbers: \"-1, 1, 0, 2, 0U, 1U, 2U, -1L, 0L, 1L, 2L, 0UL, 1UL, 2UL\"\n    # Is ignore override hashCode function\n    ignoreHashCodeFunction: \"true\"\n    # Is ignore property\n    ignorePropertyDeclaration: \"false\"\n    # Is ignore local variable\n    ignoreLocalVariableDeclaration: \"false\"\n    # Is ignore value parameter\n    ignoreValueParameter: \"true\"\n    # Is ignore constant\n    ignoreConstantDeclaration: \"true\"\n    # Is ignore property in companion object\n    ignoreCompanionObjectPropertyDeclaration: \"true\"\n    # Is ignore numbers in enum\n    ignoreEnums: \"false\"\n    # Is ignore number in ranges\n    ignoreRanges: \"false\"\n    # Is ignore number in extension function\n    ignoreExtensionFunctions: \"false\"\n    # Is ignore number in pairs created using to\n    ignorePairsCreatedUsingTo: \"false\"\n# Checks that order of enum values or constant property inside companion is correct\n- name: WRONG_DECLARATIONS_ORDER\n  enabled: true\n  configuration:\n    # Whether enum members should be sorted alphabetically\n    sortEnum: true\n    # Whether class properties should be sorted alphabetically\n    sortProperty: true\n# Checks that multiple modifiers sequence is in the correct order\n- name: WRONG_MULTIPLE_MODIFIERS_ORDER\n  enabled: true\n# Checks that identifier has appropriate name (See table of rule 1.2 part 6)\n- name: CONFUSING_IDENTIFIER_NAMING\n  enabled: true\n# Checks year in the copyright\n- name: WRONG_COPYRIGHT_YEAR\n  enabled: true\n# Inspection that checks if local variables are declared close to the first usage site\n- name: LOCAL_VARIABLE_EARLY_DECLARATION\n  enabled: true\n# Try to avoid initialize val by null (e.g. val a: Int? = null -> val a: Int = 0)\n- name: NULLABLE_PROPERTY_TYPE\n  enabled: true\n# Inspection that checks if there is a blank line before kDoc and none after\n- name: WRONG_NEWLINES_AROUND_KDOC\n  enabled: true\n# Inspection that checks if there is no blank lines before first comment\n- name: FIRST_COMMENT_NO_BLANK_LINE\n  enabled: true\n# Inspection that checks if there are blank lines between code and comment and between code start token and comment's text\n- name: COMMENT_WHITE_SPACE\n  enabled: true\n  configuration:\n    maxSpacesBeforeComment: 2\n    maxSpacesInComment: 1\n# Inspection that checks if all comment's are inside if-else code blocks. Exception is general if comment\n- name: IF_ELSE_COMMENTS\n  enabled: true\n# Type aliases provide alternative names for existing types when type's reference text is longer 25 chars\n- name: TYPE_ALIAS\n  enabled: true\n  configuration:\n    typeReferenceLength: '25' # max length of type reference\n# Checks if casting can be omitted\n- name: SMART_CAST_NEEDED\n  enabled: true\n# Checks that variables of generic types have explicit type declaration\n- name: GENERIC_VARIABLE_WRONG_DECLARATION\n  enabled: true\n# Inspection that checks if string template has redundant curly braces\n- name: STRING_TEMPLATE_CURLY_BRACES\n  enabled: true\n# Variables with `val` modifier - are immutable (read-only). Usage of such variables instead of `var` variables increases\n# robustness and readability of code, because `var` variables can be reassigned several times in the business logic.\n# This rule prohibits usage of `var`s as local variables - the only exception is accumulators and counters\n- name: SAY_NO_TO_VAR\n  enabled: true\n# Inspection that checks if string template has redundant quotes\n- name: STRING_TEMPLATE_QUOTES\n  enabled: true\n# Check if there are redundant nested if-statements, which could be collapsed into a single one by concatenating their conditions\n- name: COLLAPSE_IF_STATEMENTS\n  enabled: true\n  configuration:\n    startCollapseFromNestedLevel: 2\n# Checks that floating-point values are not used in arithmetic expressions\n- name: FLOAT_IN_ACCURATE_CALCULATIONS\n  enabled: true\n# Checks that function length isn't too long\n- name: TOO_LONG_FUNCTION\n  enabled: true\n  configuration:\n    maxFunctionLength: 30 # max length of function\n    isIncludeHeader: false # count function's header\n# Warns if there are nested functions\n- name: AVOID_NESTED_FUNCTIONS\n  enabled: true\n# Checks that lambda inside function parameters is in the end\n- name: LAMBDA_IS_NOT_LAST_PARAMETER\n  enabled: true\n# Checks that function doesn't contains too many parameters\n- name: TOO_MANY_PARAMETERS\n  enabled: true\n  configuration:\n    maxParameterListSize: '5' # max parameters size\n# Checks that function doesn't have too many nested blocks\n- name: NESTED_BLOCK\n  enabled: true\n  configuration:\n    maxNestedBlockQuantity: '4'\n# Checks that function use default values, instead overloading\n- name: WRONG_OVERLOADING_FUNCTION_ARGUMENTS\n  enabled: true\n# Checks that using runBlocking inside async block code\n- name: RUN_BLOCKING_INSIDE_ASYNC\n  enabled: true\n# Checks that the long lambda has parameters\n- name: TOO_MANY_LINES_IN_LAMBDA\n  enabled: true\n  configuration:\n    maxLambdaLength: 10 # max length of lambda without parameters\n# Checks that using unnecessary, custom label\n- name: CUSTOM_LABEL\n  enabled: true\n# Check that lambda with inner lambda doesn't use implicit parameter\n- name: PARAMETER_NAME_IN_OUTER_LAMBDA\n  enabled: true\n  configuration:\n    strictMode: true # don't let outer lambdas have `it` as parameter\n# Checks that property in constructor doesn't contains comment\n- name: KDOC_NO_CONSTRUCTOR_PROPERTY\n  enabled: true\n  configuration:\n    isParamTagsForParameters: false # create param tags for parameters without val or var\n    isParamTagsForPrivateProperties: false # create param tags for private properties\n    isParamTagsForGenericTypes: false # create param tags for generic types\n# Checks that property in KDoc present in class\n- name: KDOC_EXTRA_PROPERTY\n  enabled: true\n# There's a property in KDoc which is already present\n- name: KDOC_DUPLICATE_PROPERTY\n  enabled: true\n# Checks that KDoc in constructor has property tag but with comment inside constructor\n- name: KDOC_NO_CONSTRUCTOR_PROPERTY_WITH_COMMENT\n  enabled: true\n# if a class has single constructor, it should be converted to a primary constructor\n- name: SINGLE_CONSTRUCTOR_SHOULD_BE_PRIMARY\n  enabled: true\n# Checks if class can be made as data class\n- name: USE_DATA_CLASS\n  enabled: true\n# Checks that never use the name of a variable in the custom getter or setter\n- name: WRONG_NAME_OF_VARIABLE_INSIDE_ACCESSOR\n  enabled: true\n# Checks that classes have only one init block\n- name: MULTIPLE_INIT_BLOCKS\n  enabled: true\n# Checks that there are abstract functions in abstract class\n- name: CLASS_SHOULD_NOT_BE_ABSTRACT\n  enabled: true\n# Checks if there are any trivial getters or setters\n- name: TRIVIAL_ACCESSORS_ARE_NOT_RECOMMENDED\n  enabled: true\n# Checks that no custom getters and setters are used for properties. It is a more wide rule than TRIVIAL_ACCESSORS_ARE_NOT_RECOMMENDED\n# Kotlin compiler automatically generates `get` and `set` methods for properties and also lets the possibility to override it.\n# But in all cases it is very confusing when `get` and `set` are overridden for a developer who uses this particular class.\n# Developer expects to get the value of the property, but receives some unknown value and some extra side effect hidden by the custom getter/setter.\n# Use extra functions for it instead.\n- name: CUSTOM_GETTERS_SETTERS\n  enabled: true\n# Checks if null-check was used explicitly (for example: if (a == null))\n# Try to avoid explicit null checks (explicit comparison with `null`)\n# Kotlin is declared as [Null-safe](https://kotlinlang.org/docs/reference/null-safety.html) language.\n# But Kotlin architects wanted Kotlin to be fully compatible with Java, that's why `null` keyword was also introduced in Kotlin.\n# There are several code-structures that can be used in Kotlin to avoid null-checks. For example: `?:`,  `.let {}`, `.also {}`, e.t.c\n- name: AVOID_NULL_CHECKS\n  enabled: true\n# Checks if class instantiation can be wrapped in `apply` for better readability\n- name: COMPACT_OBJECT_INITIALIZATION\n  enabled: true\n# Checks explicit supertype qualification\n- name: USELESS_SUPERTYPE\n  enabled: true\n# Checks if extension function with the same signature don't have related classes\n- name: EXTENSION_FUNCTION_SAME_SIGNATURE\n  enabled: true\n# Checks if there is empty primary constructor\n- name: EMPTY_PRIMARY_CONSTRUCTOR\n  enabled: true\n# In case of not using field keyword in property accessors,\n# there should be explicit backing property with the name of real property\n# Example: val table get() {if (_table == null) ...} -> table should have _table\n- name: NO_CORRESPONDING_PROPERTY\n  enabled: true\n# Checks if there is class/object that can be replace with extension function\n- name: AVOID_USING_UTILITY_CLASS\n  enabled: true\n# If there is stateless class it is preferred to use object\n- name: OBJECT_IS_PREFERRED\n  enabled: true\n# If there exists negated version of function you should prefer it instead of !functionCall\n- name: INVERSE_FUNCTION_PREFERRED\n  enabled: true\n# Checks if class can be converted to inline class\n- name: INLINE_CLASS_CAN_BE_USED\n  enabled: true\n# If file contains class, then it can't contain extension functions for the same class\n- name: EXTENSION_FUNCTION_WITH_CLASS\n  enabled: true\n# Check if kts script contains other functions except run code\n- name: RUN_IN_SCRIPT\n  enabled: true\n# Check if boolean expression can be simplified\n- name: COMPLEX_BOOLEAN_EXPRESSION\n  enabled: true\n# Check if range can replace with until or `rangeTo` function with range\n- name: CONVENTIONAL_RANGE\n  enabled: true\n  configuration:\n    isRangeToIgnore: false\n# Check if there is a call of print()\\println() or console.log(). Assumption that it's a debug print\n- name: DEBUG_PRINT\n  enabled: true\n# Check that typealias name is in PascalCase\n- name: TYPEALIAS_NAME_INCORRECT_CASE\n  enabled: true\n# Should change property length - 1 to property lastIndex\n- name: USE_LAST_INDEX\n  enabled: true\n# Only properties from the primary constructor should be documented in a @property tag in class KDoc\n- name: KDOC_NO_CLASS_BODY_PROPERTIES_IN_HEADER\n  enabled: true\n"
  },
  {
    "path": "diktat-rules/src/main/resources/diktat-analysis.yml",
    "content": "# Common configuration\n- name: DIKTAT_COMMON\n  configuration:\n    # put your package name here - it will be autofixed and checked\n    domainName: your.name.here\n    testDirs: test\n    # expected values:  disabledChapters: \"Naming, Comments, General, Variables, Functions, Classes\"\n    # or: \"1, 2, 3, 4, 5, 6\"\n    disabledChapters: \"\"\n    kotlinVersion: 2.1\n    srcDirectories: \"main\"\n# Checks that the Class/Enum/Interface name matches Pascal case\n- name: CLASS_NAME_INCORRECT\n  enabled: true\n  # all code blocks with MyAnnotation will be ignored and not checked\n  ignoreAnnotated: [ MyAnnotation ]\n# Checks that CONSTANT (treated as const val from companion object or class level) is in non UPPER_SNAKE_CASE\n- name: CONSTANT_UPPERCASE\n  enabled: true\n# Checks that enum value is in upper SNAKE_CASE or in PascalCase depending on the config. UPPER_SNAKE_CASE is the default, but can be changed by 'enumStyle' config\n- name: ENUM_VALUE\n  enabled: true\n  configuration:\n    # Two options: SNAKE_CASE (default), PascalCase\n    enumStyle: SNAKE_CASE\n# Checks that class which extends any Exception class has Exception suffix\n- name: EXCEPTION_SUFFIX\n  enabled: true\n# Checks that file name has extension\n- name: FILE_NAME_INCORRECT\n  enabled: true\n# Checks that file name matches class name, if it is only one class in file\n- name: FILE_NAME_MATCH_CLASS\n  enabled: true\n# Checks that functions/methods which return boolean have special prefix like \"is/should/e.t.c\"\n- name: FUNCTION_BOOLEAN_PREFIX\n  enabled: true\n  configuration:\n    allowedPrefixes: \"\" # A list of functions that return boolean and are allowed to use. Input is in a form \"foo, bar\".\n# Checks that function/method name is in lowerCamelCase\n- name: FUNCTION_NAME_INCORRECT_CASE\n  enabled: true\n# Checks that typealias name is in PascalCase\n- name: TYPEALIAS_NAME_INCORRECT_CASE\n  enabled: true\n# Checks that generic name doesn't contain more than 1 letter (capital). It can be followed by numbers, example: T12, T\n- name: GENERIC_NAME\n  enabled: true\n# Identifier length should be in range [2,64] except names that used in industry like {i, j} and 'e' for catching exceptions\n- name: IDENTIFIER_LENGTH\n  enabled: true\n# Checks that the object matches PascalCase\n- name: OBJECT_NAME_INCORRECT\n  enabled: true\n# Checks that package name is in correct (lower) case\n- name: PACKAGE_NAME_INCORRECT_CASE\n  enabled: true\n# Checks that package name starts with the company's domain\n- name: PACKAGE_NAME_INCORRECT_PREFIX\n  enabled: false\n# Checks that package name does not have incorrect symbols like underscore or non-ASCII letters/digits\n- name: PACKAGE_NAME_INCORRECT_SYMBOLS\n  enabled: true\n# Checks that the path for a file matches with a package name\n- name: PACKAGE_NAME_INCORRECT_PATH\n  enabled: false\n# Checks that package name is in the file\n- name: PACKAGE_NAME_MISSING\n  enabled: true\n# Checks that variable does not have prefix (like mVariable or M_VARIABLE)\n- name: VARIABLE_HAS_PREFIX\n  enabled: true\n# Checks that variable does not contain one single letter, only exceptions are fixed names that used in industry like {i, j}\n- name: VARIABLE_NAME_INCORRECT\n  enabled: true\n# Checks that the name of variable is in lowerCamelCase and contains only ASCII letters\n- name: VARIABLE_NAME_INCORRECT_FORMAT\n  enabled: true\n# Checks that functions have kdoc\n- name: MISSING_KDOC_ON_FUNCTION\n  enabled: true\n# Checks that on file level internal or public class or function has missing KDoc\n- name: MISSING_KDOC_TOP_LEVEL\n  enabled: true\n# Checks that accessible internal elements (protected, public, internal) in a class are documented\n- name: MISSING_KDOC_CLASS_ELEMENTS\n  enabled: true\n# Checks that accessible method parameters are documented in KDoc\n- name: KDOC_WITHOUT_PARAM_TAG\n  enabled: true\n# Checks that accessible method explicit return type is documented in KDoc\n- name: KDOC_WITHOUT_RETURN_TAG\n  enabled: true\n# Checks that accessible method throw keyword is documented in KDoc\n- name: KDOC_WITHOUT_THROWS_TAG\n  enabled: true\n# Checks that KDoc is not empty\n- name: KDOC_EMPTY_KDOC\n  enabled: true\n# Checks that underscore is correctly used to split package naming\n- name: INCORRECT_PACKAGE_SEPARATOR\n  enabled: true\n# Checks that code block doesn't contain kdoc comments\n- name: COMMENTED_BY_KDOC\n  enabled: true\n# Checks that there is no @deprecated tag in kdoc\n- name: KDOC_NO_DEPRECATED_TAG\n  enabled: true\n# Checks that there is no empty content in kdoc tags\n- name: KDOC_NO_EMPTY_TAGS\n  enabled: true\n# Checks that there is only one space after kdoc tag\n- name: KDOC_WRONG_SPACES_AFTER_TAG\n  enabled: true\n# Checks tags order in kDoc. `@param`, `@return`, `@throws`\n- name: KDOC_WRONG_TAGS_ORDER\n  enabled: true\n# Checks that there is no newline of empty KDoc line (with leading asterisk) between `@param`, `@return`, `@throws` tags\n- name: KDOC_NO_NEWLINES_BETWEEN_BASIC_TAGS\n  enabled: true\n# Checks that block of tags @param, @return, @throws is separated from previous part of KDoc by exactly one empty line\n- name: KDOC_NEWLINES_BEFORE_BASIC_TAGS\n  enabled: true\n# Checks that special tags `@apiNote`, `@implNote`, `@implSpec` have exactly one empty line after\n- name: KDOC_NO_NEWLINE_AFTER_SPECIAL_TAGS\n  enabled: true\n# Checks that kdoc does not contain @author tag or date\n- name: KDOC_CONTAINS_DATE_OR_AUTHOR\n  enabled: true\n  configuration:\n    versionRegex: \\d+\\.\\d+\\.\\d+[-.\\w\\d]*\n# Checks that KDoc does not contain single line with words 'return', 'get' or 'set'\n- name: KDOC_TRIVIAL_KDOC_ON_FUNCTION\n  enabled: true\n# Checks that there is newline after header KDoc\n- name: HEADER_WRONG_FORMAT\n  enabled: true\n# Checks that file with zero or >1 classes has header KDoc\n- name: HEADER_MISSING_IN_NON_SINGLE_CLASS_FILE\n  enabled: true\n# Checks that copyright exists on top of file and is properly formatted (as a block comment)\n- name: HEADER_MISSING_OR_WRONG_COPYRIGHT\n  enabled: true\n  configuration:\n    isCopyrightMandatory: false\n    copyrightText: 'Copyright (c) Your Company Name Here. 2010-;@currYear;'\n# Checks that header kdoc is located before package directive\n- name: HEADER_NOT_BEFORE_PACKAGE\n  enabled: true\n# Checks that file does not contain lines > maxSize\n- name: FILE_IS_TOO_LONG\n  enabled: true\n  configuration:\n    # number of lines\n    maxSize: '2000'\n# Checks that file does not contain commented out code\n- name: COMMENTED_OUT_CODE\n  enabled: true\n# Checks that file does not contain only comments, imports and package directive\n- name: FILE_CONTAINS_ONLY_COMMENTS\n  enabled: true\n# Orders imports alphabetically\n- name: FILE_UNORDERED_IMPORTS\n  enabled: true\n  configuration:\n    # use logical imports grouping with sorting inside of a group\n    useRecommendedImportsOrder: true\n# Checks that general order of code parts is right\n- name: FILE_INCORRECT_BLOCKS_ORDER\n  enabled: true\n# Checks that there is exactly one line between code blocks\n- name: FILE_NO_BLANK_LINE_BETWEEN_BLOCKS\n  enabled: true\n# Checks that there is no wildcard imports. Exception: allowedWildcards\n- name: FILE_WILDCARD_IMPORTS\n  enabled: true\n  configuration:\n    allowedWildcards: \"\" # Allowed wildcards for imports (e.g. \"import com.saveourtool.diktat.*, import org.jetbrains.kotlin.*\")\n    useRecommendedImportsOrder: true\n# Checks unused imports\n- name: UNUSED_IMPORT\n  enabled: true\n  configuration:\n    deleteUnusedImport: true\n# Checks that braces are used in if, else, when, for, do, and while statements. Exception: single line ternary operator statement\n- name: NO_BRACES_IN_CONDITIONALS_AND_LOOPS\n  enabled: true\n# Checks that the declaration part of a class-like code structures (class/interface/etc.) is in the proper order\n- name: WRONG_ORDER_IN_CLASS_LIKE_STRUCTURES\n  enabled: true\n# Checks that properties with comments are separated by a blank line\n- name: BLANK_LINE_BETWEEN_PROPERTIES\n  enabled: true\n# Checks top level order\n- name: TOP_LEVEL_ORDER\n  enabled: true\n# Checks that non-empty code blocks with braces follow the K&R style (1TBS or OTBS style)\n- name: BRACES_BLOCK_STRUCTURE_ERROR\n  enabled: true\n  configuration:\n    openBraceNewline: 'True'\n    closeBraceNewline: 'True'\n# Checks that indentation is correct\n- name: WRONG_INDENTATION\n  enabled: true\n  configuration:\n    # Is newline at the end of a file needed\n    newlineAtEnd: true\n    # If true: in parameter list when parameters are split by newline they are indented with two indentations instead of one\n    extendedIndentOfParameters: false\n    # If true: if first parameter in parameter list is on the same line as opening parenthesis, then other parameters can be aligned with it\n    alignedParameters: true\n    # If true, expression bodies which begin on a separate line are indented\n    # using a continuation indent. The default is false.\n    #\n    # This flag is called CONTINUATION_INDENT_FOR_EXPRESSION_BODIES in IDEA and\n    # ij_kotlin_continuation_indent_for_expression_bodies in .editorconfig.\n    extendedIndentForExpressionBodies: false\n    # If true: if expression is split by newline after operator like +/-/`*`, then the next line is indented with two indentations instead of one\n    extendedIndentAfterOperators: true\n    # If true: when dot qualified expression starts on a new line, this line will be indented with two indentations instead of one\n    extendedIndentBeforeDot: false\n    # The indentation size for each file\n    indentationSize: 4\n# Checks that there is no empty blocks in a file.\n# If allowEmptyBlocks is true, checks that it follows correct style (have a newline)\n- name: EMPTY_BLOCK_STRUCTURE_ERROR\n  enabled: true\n  configuration:\n    # Whether a newline after `{` is required in an empty block\n    styleEmptyBlockWithNewline: 'True'\n    allowEmptyBlocks: 'False'\n# Checks that there is no more than one statement per line\n- name: MORE_THAN_ONE_STATEMENT_PER_LINE\n  enabled: true\n# Checks that the line length is < lineLength parameter\n- name: LONG_LINE\n  enabled: true\n  configuration:\n    lineLength: '120'\n# Checks that semicolons are not used at the end of a line\n- name: REDUNDANT_SEMICOLON\n  enabled: true\n# Checks that line breaks follow code style guide: rule 3.6\n- name: WRONG_NEWLINES\n  enabled: true\n  configuration:\n    # If the number of parameters on one line is more than this threshold, all parameters will be placed on separate lines.\n    maxParametersInOneLine: 2\n    # 3 by default.\n    maxCallsInOneLine: 3\n# Checks trailing comma\n- name: TRAILING_COMMA\n  enabled: true\n  configuration:\n    # VALUE_ARGUMENT\n    valueArgument: false\n    # VALUE_PARAMETER\n    valueParameter: false\n    # REFERENCE_EXPRESSION\n    indices: false\n    # WHEN_CONDITION_WITH_EXPRESSION\n    whenConditions: false\n    # STRING_TEMPLATE\n    collectionLiteral: false\n    # TYPE_PROJECTION\n    typeArgument: false\n    # TYPE_PARAMETER\n    typeParameter: false\n    # DESTRUCTURING_DECLARATION_ENTRY\n    destructuringDeclaration: false\n# Checks that there are not too many consecutive spaces in line\n- name: TOO_MANY_CONSECUTIVE_SPACES\n  enabled: true\n  configuration:\n    # Maximum allowed number of consecutive spaces (not counting indentation)\n    maxSpaces: '1'\n    # Whether formatting for enums should be kept without checking\n    saveInitialFormattingForEnums: false\n# Inspection that checks if a long dot qualified expression is used in condition or as an argument\n- name: COMPLEX_EXPRESSION\n  enabled: true\n# Checks that blank lines are used correctly.\n# For example: triggers when there are too many blank lines between function declaration\n- name: TOO_MANY_BLANK_LINES\n  enabled: true\n# Checks that usage of horizontal spaces doesn't violate code style guide\n- name: WRONG_WHITESPACE\n  enabled: true\n# Checks that backticks (``) are not used in the identifier name, except the case when it is test method (marked with @Test annotation)\n- name: BACKTICKS_PROHIBITED\n  enabled: true\n# Checks that a single line concatenation of strings is not used\n- name: STRING_CONCATENATION\n  enabled: true\n# Checks that each when statement have else in the end\n- name: WHEN_WITHOUT_ELSE\n  enabled: true\n# Checks that annotation is on a single line\n- name: ANNOTATION_NEW_LINE\n  enabled: true\n# Checks that method annotated with `Preview` annotation is private and has Preview suffix\n- name: PREVIEW_ANNOTATION\n  enabled: true\n# Checks that enum structure is correct: enum entries should be separated by comma and line break and last entry should have semicolon in the end.\n- name: ENUMS_SEPARATED\n  enabled: true\n# Checks that value on integer or float constant is not too big\n- name: LONG_NUMERICAL_VALUES_SEPARATED\n  enabled: true\n  configuration:\n    # Maximum number of digits which are not split\n    maxNumberLength: '5'\n    # Maximum number of digits between separators\n    maxBlockLength: '3'\n# Checks magic number\n- name: MAGIC_NUMBER\n  enabled: true\n  configuration:\n    # Ignore numbers from test\n    ignoreTest: \"true\"\n    # Ignore numbers\n    ignoreNumbers: \"-1, 1, 0, 2, 0U, 1U, 2U, -1L, 0L, 1L, 2L, 0UL, 1UL, 2UL\"\n    # Is ignore override hashCode function\n    ignoreHashCodeFunction: \"true\"\n    # Is ignore property\n    ignorePropertyDeclaration: \"false\"\n    # Is ignore local variable\n    ignoreLocalVariableDeclaration: \"false\"\n    # Is ignore value parameter\n    ignoreValueParameter: \"true\"\n    # Is ignore constant\n    ignoreConstantDeclaration: \"true\"\n    # Is ignore property in companion object\n    ignoreCompanionObjectPropertyDeclaration: \"true\"\n    # Is ignore numbers in enum\n    ignoreEnums: \"false\"\n    # Is ignore number in ranges\n    ignoreRanges: \"false\"\n    # Is ignore number in extension function\n    ignoreExtensionFunctions: \"false\"\n    # Is ignore number in pairs created using to\n    ignorePairsCreatedUsingTo: \"false\"\n# Checks that order of enum values or constant property inside companion is correct\n- name: WRONG_DECLARATIONS_ORDER\n  enabled: true\n  configuration:\n    # Whether enum members should be sorted alphabetically\n    sortEnum: true\n    # Whether class properties should be sorted alphabetically\n    sortProperty: true\n# Checks that multiple modifiers sequence is in the correct order\n- name: WRONG_MULTIPLE_MODIFIERS_ORDER\n  enabled: true\n# Checks that identifier has appropriate name (See table of rule 1.2 part 6)\n- name: CONFUSING_IDENTIFIER_NAMING\n  enabled: true\n# Checks year in the copyright\n- name: WRONG_COPYRIGHT_YEAR\n  enabled: true\n# Inspection that checks if local variables are declared close to the first usage site\n- name: LOCAL_VARIABLE_EARLY_DECLARATION\n  enabled: true\n# Try to avoid initialize val by null (e.g. val a: Int? = null -> val a: Int = 0)\n- name: NULLABLE_PROPERTY_TYPE\n  enabled: true\n# Inspection that checks if there is a blank line before kDoc and none after\n- name: WRONG_NEWLINES_AROUND_KDOC\n  enabled: true\n# Inspection that checks if there is no blank lines before first comment\n- name: FIRST_COMMENT_NO_BLANK_LINE\n  enabled: true\n# Inspection that checks if there are blank lines between code and comment and between code start token and comment's text\n- name: COMMENT_WHITE_SPACE\n  enabled: true\n  configuration:\n    maxSpacesBeforeComment: 2\n    maxSpacesInComment: 1\n# Inspection that checks if all comment's are inside if-else code blocks. Exception is general if comment\n- name: IF_ELSE_COMMENTS\n  enabled: true\n# Type aliases provide alternative names for existing types when type's reference text is longer 25 chars\n- name: TYPE_ALIAS\n  enabled: true\n  configuration:\n    typeReferenceLength: '25' # max length of type reference\n# Checks if casting can be omitted\n- name: SMART_CAST_NEEDED\n  enabled: true\n# Checks that variables of generic types have explicit type declaration\n- name: GENERIC_VARIABLE_WRONG_DECLARATION\n  enabled: true\n# Inspection that checks if string template has redundant curly braces\n- name: STRING_TEMPLATE_CURLY_BRACES\n  enabled: true\n# Variables with `val` modifier - are immutable (read-only). Usage of such variables instead of `var` variables increases\n# robustness and readability of code, because `var` variables can be reassigned several times in the business logic.\n# This rule prohibits usage of `var`s as local variables - the only exception is accumulators and counters\n- name: SAY_NO_TO_VAR\n  enabled: true\n# Inspection that checks if string template has redundant quotes\n- name: STRING_TEMPLATE_QUOTES\n  enabled: true\n# Check if there are redundant nested if-statements, which could be collapsed into a single one by concatenating their conditions\n- name: COLLAPSE_IF_STATEMENTS\n  enabled: true\n  configuration:\n    startCollapseFromNestedLevel: 2\n# Checks that floating-point values are not used in arithmetic expressions\n- name: FLOAT_IN_ACCURATE_CALCULATIONS\n  enabled: true\n# Checks that function length isn't too long\n- name: TOO_LONG_FUNCTION\n  enabled: true\n  configuration:\n    maxFunctionLength: '30' # max length of function\n    isIncludeHeader: 'false' # count function's header\n# Warns if there are nested functions\n- name: AVOID_NESTED_FUNCTIONS\n  enabled: true\n# Checks that lambda inside function parameters is in the end\n- name: LAMBDA_IS_NOT_LAST_PARAMETER\n  enabled: true\n# Checks that function doesn't contains too many parameters\n- name: TOO_MANY_PARAMETERS\n  enabled: true\n  configuration:\n    maxParameterListSize: '5' # max parameters size\n# Checks that function doesn't have too many nested blocks\n- name: NESTED_BLOCK\n  enabled: true\n  configuration:\n    maxNestedBlockQuantity: '4'\n# Checks that function use default values, instead overloading\n- name: WRONG_OVERLOADING_FUNCTION_ARGUMENTS\n  enabled: true\n# Checks that using runBlocking inside async block code\n- name: RUN_BLOCKING_INSIDE_ASYNC\n  enabled: true\n# Checks that property in constructor doesn't contain comment\n- name: KDOC_NO_CONSTRUCTOR_PROPERTY\n  enabled: true\n  configuration:\n    isParamTagsForParameters: true # create param tags for parameters without val or var\n    isParamTagsForPrivateProperties: true # create param tags for private properties\n    isParamTagsForGenericTypes: true # create param tags for generic types\n# Checks that the long lambda has parameters\n- name: TOO_MANY_LINES_IN_LAMBDA\n  enabled: true\n  configuration:\n    maxLambdaLength: 10 # max length of lambda without parameters\n# Checks that using unnecessary, custom label\n- name: CUSTOM_LABEL\n  enabled: true\n# Check that lambda with inner lambda doesn't use implicit parameter\n- name: PARAMETER_NAME_IN_OUTER_LAMBDA\n  enabled: true\n  configuration:\n    strictMode: true # don't let outer lambdas have `it` as parameter\n# Checks that property in KDoc present in class\n- name: KDOC_EXTRA_PROPERTY\n  enabled: true\n# There's a property in KDoc which is already present\n- name: KDOC_DUPLICATE_PROPERTY\n  enabled: true\n# Checks that KDoc in constructor has property tag but with comment inside constructor\n- name: KDOC_NO_CONSTRUCTOR_PROPERTY_WITH_COMMENT\n  enabled: true\n# if a class has single constructor, it should be converted to a primary constructor\n- name: SINGLE_CONSTRUCTOR_SHOULD_BE_PRIMARY\n  enabled: true\n# Checks if class can be made as data class\n- name: USE_DATA_CLASS\n  enabled: true\n# Checks that never use the name of a variable in the custom getter or setter\n- name: WRONG_NAME_OF_VARIABLE_INSIDE_ACCESSOR\n  enabled: true\n# Checks that classes have only one init block\n- name: MULTIPLE_INIT_BLOCKS\n  enabled: true\n# Checks that there are abstract functions in abstract class\n- name: CLASS_SHOULD_NOT_BE_ABSTRACT\n  enabled: true\n# Checks if there are any trivial getters or setters\n- name: TRIVIAL_ACCESSORS_ARE_NOT_RECOMMENDED\n  enabled: true\n# Checks that no custom getters and setters are used for properties. It is a more wide rule than TRIVIAL_ACCESSORS_ARE_NOT_RECOMMENDED\n# Kotlin compiler automatically generates `get` and `set` methods for properties and also lets the possibility to override it.\n# But in all cases it is very confusing when `get` and `set` are overridden for a developer who uses this particular class.\n# Developer expects to get the value of the property, but receives some unknown value and some extra side effect hidden by the custom getter/setter.\n# Use extra functions for it instead.\n- name: CUSTOM_GETTERS_SETTERS\n  enabled: true\n# Checks if null-check was used explicitly (for example: if (a == null))\n# Try to avoid explicit null checks (explicit comparison with `null`)\n# Kotlin is declared as [Null-safe](https://kotlinlang.org/docs/reference/null-safety.html) language.\n# But Kotlin architects wanted Kotlin to be fully compatible with Java, that's why `null` keyword was also introduced in Kotlin.\n# There are several code-structures that can be used in Kotlin to avoid null-checks. For example: `?:`,  `.let {}`, `.also {}`, e.t.c\n- name: AVOID_NULL_CHECKS\n  enabled: true\n# Checks if class instantiation can be wrapped in `apply` for better readability\n- name: COMPACT_OBJECT_INITIALIZATION\n  enabled: true\n# Checks explicit supertype qualification\n- name: USELESS_SUPERTYPE\n  enabled: true\n# Checks if extension function with the same signature don't have related classes\n- name: EXTENSION_FUNCTION_SAME_SIGNATURE\n  enabled: true\n# Checks if there is empty primary constructor\n- name: EMPTY_PRIMARY_CONSTRUCTOR\n  enabled: true\n# In case of not using field keyword in property accessors,\n# there should be explicit backing property with the name of real property\n# Example: val table get() {if (_table == null) ...} -> table should have _table\n- name: NO_CORRESPONDING_PROPERTY\n  enabled: true\n# Checks if there is class/object that can be replace with extension function\n- name: AVOID_USING_UTILITY_CLASS\n  enabled: true\n# If there is stateless class it is preferred to use object\n- name: OBJECT_IS_PREFERRED\n  enabled: true\n# If there exists negated version of function you should prefer it instead of !functionCall\n- name: INVERSE_FUNCTION_PREFERRED\n  enabled: true\n# Checks if class can be converted to inline class\n- name: INLINE_CLASS_CAN_BE_USED\n  enabled: true\n# If file contains class, then it can't contain extension functions for the same class\n- name: EXTENSION_FUNCTION_WITH_CLASS\n  enabled: true\n# Check if kts script contains other functions except run code\n- name: RUN_IN_SCRIPT\n  enabled: true\n# Check if boolean expression can be simplified\n- name: COMPLEX_BOOLEAN_EXPRESSION\n  enabled: true\n# Check if range can replace with until or `rangeTo` function with range\n- name: CONVENTIONAL_RANGE\n  enabled: true\n  configuration:\n    isRangeToIgnore: false\n# Check if there is a call of print()\\println() or console.log(). Assumption that it's a debug print\n- name: DEBUG_PRINT\n  enabled: true\n# Check that typealias name is in PascalCase\n- name: TYPEALIAS_NAME_INCORRECT_CASE\n  enabled: true\n# Should change property length - 1 to property lastIndex\n- name: USE_LAST_INDEX\n  enabled: true\n# Only properties from the primary constructor should be documented in a @property tag in class KDoc\n- name: KDOC_NO_CLASS_BODY_PROPERTIES_IN_HEADER\n  enabled: true\n"
  },
  {
    "path": "diktat-rules/src/test/kotlin/com/saveourtool/diktat/ruleset/chapter1/EnumValueCaseTest.kt",
    "content": "package com.saveourtool.diktat.ruleset.chapter1\n\nimport com.saveourtool.diktat.common.config.rules.RulesConfig\nimport com.saveourtool.diktat.common.config.rules.getRuleConfig\nimport com.saveourtool.diktat.ruleset.constants.Warnings\nimport com.saveourtool.diktat.ruleset.rules.chapter1.IdentifierNaming\nimport com.saveourtool.diktat.util.FixTestBase\n\nimport generated.WarningNames\nimport org.junit.jupiter.api.Tag\nimport org.junit.jupiter.api.Test\nimport org.junit.jupiter.api.assertThrows\n\nclass EnumValueCaseTest : FixTestBase(\"test/paragraph1/naming\", ::IdentifierNaming) {\n    private val rulesConfigSnakeCaseEnum: List<RulesConfig> = listOf(\n        RulesConfig(Warnings.ENUM_VALUE.name, true,\n            mapOf(\"enumStyle\" to \"snakeCase\"))\n    )\n    private val rulesConfigPascalCaseEnum: List<RulesConfig> = listOf(\n        RulesConfig(Warnings.ENUM_VALUE.name, true,\n            mapOf(\"enumStyle\" to \"pascalCase\"))\n    )\n    private val rulesConfigEnumUnknownStyle: List<RulesConfig> = listOf(\n        RulesConfig(Warnings.ENUM_VALUE.name, true,\n            mapOf(\"enumStyle\" to \"otherCase\"))\n    )\n\n    @Test\n    @Tag(WarningNames.ENUM_VALUE)\n    fun `incorrect enum snake case value fix`() {\n        fixAndCompare(\"enum_/EnumValueSnakeCaseExpected.kt\", \"enum_/EnumValueSnakeCaseTest.kt\", rulesConfigSnakeCaseEnum)\n    }\n\n    @Test\n    @Tag(WarningNames.ENUM_VALUE)\n    fun `incorrect enum pascal case value fix`() {\n        fixAndCompare(\"enum_/EnumValuePascalCaseExpected.kt\", \"enum_/EnumValuePascalCaseTest.kt\", rulesConfigPascalCaseEnum)\n    }\n\n    @Test\n    @Tag(WarningNames.ENUM_VALUE)\n    fun `incorrect enum unknown style`() {\n        assertThrows<IllegalStateException> {\n            IdentifierNaming.IdentifierNamingConfiguration(\n                rulesConfigEnumUnknownStyle.getRuleConfig(Warnings.ENUM_VALUE)\n                    ?.configuration ?: emptyMap()\n            )\n        }\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/test/kotlin/com/saveourtool/diktat/ruleset/chapter1/IdentifierNamingFixTest.kt",
    "content": "package com.saveourtool.diktat.ruleset.chapter1\n\nimport com.saveourtool.diktat.common.config.rules.RulesConfig\nimport com.saveourtool.diktat.ruleset.rules.chapter1.IdentifierNaming\nimport com.saveourtool.diktat.util.FixTestBase\n\nimport generated.WarningNames\nimport org.junit.jupiter.api.Tag\nimport org.junit.jupiter.api.Test\n\nclass IdentifierNamingFixTest : FixTestBase(\n    \"test/paragraph1/naming\",\n    ::IdentifierNaming,\n    listOf(\n        RulesConfig(\"PACKAGE_NAME_INCORRECT\", false, emptyMap()),\n        RulesConfig(\"PACKAGE_NAME_INCORRECT_PREFIX\", false, emptyMap())\n    )\n) {\n    @Test\n    @Tag(WarningNames.CLASS_NAME_INCORRECT)\n    fun `regression in VARIABLE_NAME_INCORRECT_FORMAT`() {\n        fixAndCompare(\"identifiers/IdentifierNameRegressionExpected.kt\", \"identifiers/IdentifierNameRegressionTest.kt\")\n    }\n\n    @Test\n    @Tag(WarningNames.CLASS_NAME_INCORRECT)\n    fun `incorrect class name fix`() {\n        fixAndCompare(\"class_/IncorrectClassNameExpected.kt\", \"class_/IncorrectClassNameTest.kt\")\n    }\n\n    @Test\n    @Tag(WarningNames.OBJECT_NAME_INCORRECT)\n    fun `incorrect object name fix`() {\n        fixAndCompare(\"object_/IncorrectObjectNameExpected.kt\", \"object_/IncorrectObjectNameTest.kt\")\n    }\n\n    @Test\n    @Tag(WarningNames.ENUM_VALUE)\n    fun `incorrect enum values case fix`() {\n        fixAndCompare(\"enum_/EnumValueSnakeCaseExpected.kt\", \"enum_/EnumValueSnakeCaseTest.kt\")\n    }\n\n    @Test\n    @Tag(WarningNames.CONSTANT_UPPERCASE)\n    fun `incorrect constant name case fix`() {\n        fixAndCompare(\"identifiers/ConstantValNameExpected.kt\", \"identifiers/ConstantValNameTest.kt\")\n    }\n\n    @Test\n    @Tag(WarningNames.VARIABLE_NAME_INCORRECT_FORMAT)\n    fun `incorrect variable name case fix`() {\n        fixAndCompare(\"identifiers/VariableNamingExpected.kt\", \"identifiers/VariableNamingTest.kt\")\n    }\n\n    @Test\n    @Tag(WarningNames.VARIABLE_HAS_PREFIX)\n    fun `incorrect variable prefix fix`() {\n        fixAndCompare(\"identifiers/PrefixInNameExpected.kt\", \"identifiers/PrefixInNameTest.kt\")\n    }\n\n    @Test\n    @Tag(WarningNames.VARIABLE_NAME_INCORRECT_FORMAT)\n    fun `incorrect lambda argument case fix`() {\n        fixAndCompare(\"identifiers/LambdaArgExpected.kt\", \"identifiers/LambdaArgTest.kt\")\n    }\n\n    @Test\n    @Tag(WarningNames.TYPEALIAS_NAME_INCORRECT_CASE)\n    fun `typeAlias name incorrect`() {\n        fixAndCompare(\"identifiers/TypeAliasNameExpected.kt\", \"identifiers/TypeAliasNameTest.kt\")\n    }\n\n    @Test\n    @Tag(WarningNames.TYPEALIAS_NAME_INCORRECT_CASE)\n    fun `should update property name in KDoc after fixing`() {\n        fixAndCompare(\"identifiers/PropertyInKdocExpected.kt\", \"identifiers/PropertyInKdocTest.kt\")\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/test/kotlin/com/saveourtool/diktat/ruleset/chapter1/IdentifierNamingWarnTest.kt",
    "content": "@file:Suppress(\n    \"LargeClass\"\n)\n\npackage com.saveourtool.diktat.ruleset.chapter1\n\nimport com.saveourtool.diktat.common.config.rules.DIKTAT_RULE_SET_ID\nimport com.saveourtool.diktat.common.config.rules.RulesConfig\nimport com.saveourtool.diktat.ruleset.constants.Warnings.BACKTICKS_PROHIBITED\nimport com.saveourtool.diktat.ruleset.constants.Warnings.CLASS_NAME_INCORRECT\nimport com.saveourtool.diktat.ruleset.constants.Warnings.CONFUSING_IDENTIFIER_NAMING\nimport com.saveourtool.diktat.ruleset.constants.Warnings.CONSTANT_UPPERCASE\nimport com.saveourtool.diktat.ruleset.constants.Warnings.ENUM_VALUE\nimport com.saveourtool.diktat.ruleset.constants.Warnings.EXCEPTION_SUFFIX\nimport com.saveourtool.diktat.ruleset.constants.Warnings.FUNCTION_BOOLEAN_PREFIX\nimport com.saveourtool.diktat.ruleset.constants.Warnings.GENERIC_NAME\nimport com.saveourtool.diktat.ruleset.constants.Warnings.IDENTIFIER_LENGTH\nimport com.saveourtool.diktat.ruleset.constants.Warnings.OBJECT_NAME_INCORRECT\nimport com.saveourtool.diktat.ruleset.constants.Warnings.VARIABLE_HAS_PREFIX\nimport com.saveourtool.diktat.ruleset.constants.Warnings.VARIABLE_NAME_INCORRECT\nimport com.saveourtool.diktat.ruleset.constants.Warnings.VARIABLE_NAME_INCORRECT_FORMAT\nimport com.saveourtool.diktat.ruleset.rules.chapter1.IdentifierNaming\nimport com.saveourtool.diktat.util.LintTestBase\n\nimport com.saveourtool.diktat.api.DiktatError\nimport com.saveourtool.diktat.ruleset.constants.Warnings\nimport com.saveourtool.diktat.ruleset.utils.getFirstChildWithType\nimport com.saveourtool.diktat.ruleset.utils.hasAnyChildOfTypes\nimport com.saveourtool.diktat.ruleset.utils.prettyPrint\nimport generated.WarningNames\nimport org.jetbrains.kotlin.KtNodeTypes\nimport org.jetbrains.kotlin.com.intellij.lang.ASTNode\nimport org.jetbrains.kotlin.lexer.KtTokens\nimport org.junit.jupiter.api.Tag\nimport org.junit.jupiter.api.Tags\nimport org.junit.jupiter.api.Test\n\nclass IdentifierNamingWarnTest : LintTestBase(::IdentifierNaming) {\n    private val ruleId: String = \"$DIKTAT_RULE_SET_ID:${IdentifierNaming.NAME_ID}\"\n    private val rulesConfigBooleanFunctions: List<RulesConfig> = listOf(\n        RulesConfig(FUNCTION_BOOLEAN_PREFIX.name, true,\n            mapOf(\"allowedPrefixes\" to \"equals, equivalent, foo\"))\n    )\n    private val rulesConfigConstantUpperCase = listOf(\n        RulesConfig(CONSTANT_UPPERCASE.name, true, mapOf(\n            \"exceptionConstNames\" to \"serialVersionUID\"\n        ))\n    )\n\n    // ======== checks for generics ========\n    @Test\n    @Tag(WarningNames.GENERIC_NAME)\n    fun `generic class - single capital letter, can be followed by a number  (check - positive1)`() {\n        val code =\n            \"\"\"\n                package com.saveourtool.diktat.test\n\n                class TreeNode<T>(val value: T?, val next: TreeNode<T>? = null)\n\n            \"\"\".trimIndent()\n        lintMethod(code)\n    }\n\n    @Test\n    @Tag(WarningNames.GENERIC_NAME)\n    fun `generic class - single capital letter, can be followed by a number  (check - positive2)`() {\n        val code =\n            \"\"\"\n                package com.saveourtool.diktat.test\n\n                class TreeNode<T123>(val value: T?, val next: TreeNode<T>? = null)\n\n            \"\"\".trimIndent()\n        lintMethod(code)\n    }\n\n    @Test\n    @Tag(WarningNames.GENERIC_NAME)\n    fun `anonymous function`() {\n        val code = \"\"\"\n            package com.saveourtool.diktat.test\n\n            fun foo() {\n                val sum: (Int) -> Int = fun(x): Int = x + x\n            }\n\n        \"\"\".trimIndent()\n        lintMethod(code)\n    }\n\n    @Test\n    @Tag(WarningNames.GENERIC_NAME)\n    fun `generic class - single capital letter, can be followed by a number  (check - negative1)`() {\n        val code =\n            \"\"\"\n                package com.saveourtool.diktat.test\n\n                class TreeNode<a>(val value: T?, val next: TreeNode<T>? = null)\n\n            \"\"\".trimIndent()\n        lintMethod(code, DiktatError(\n            3, 15, ruleId, \"${GENERIC_NAME.warnText()} <a>\", false)\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.GENERIC_NAME)\n    fun `generic class - single capital letter, can be followed by a number  (check - negative2)`() {\n        val code =\n            \"\"\"\n                package com.saveourtool.diktat.test\n\n                class TreeNode<TBBB>(val value: T?, val next: TreeNode<T>? = null)\n\n            \"\"\".trimIndent()\n        lintMethod(code, DiktatError(\n            3, 15, ruleId, \"${GENERIC_NAME.warnText()} <TBBB>\", false)\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.GENERIC_NAME)\n    fun `generic method - single capital letter, can be followed by a number  (check)`() {\n        val code =\n            \"\"\"\n                package com.saveourtool.diktat.test\n\n                fun <T> makeLinkedList(vararg elements: T): TreeNode<T>? {\n                    var node: TreeNode<T>? = null\n                    for (element in elements.reversed()) {\n                         node = TreeNode(element, node)\n                    }\n                    return node\n                }\n            \"\"\".trimIndent()\n        lintMethod(code)\n    }\n\n    // ======== checks for variables and class names ========\n    @Test\n    @Tag(WarningNames.CLASS_NAME_INCORRECT)\n    fun `check class name (check)`() {\n        val code =\n            \"\"\"\n                class incorrectNAME {}\n                class IncorrectNAME {}\n            \"\"\"\n        lintMethod(code,\n            DiktatError(2, 23, ruleId, \"${CLASS_NAME_INCORRECT.warnText()} incorrectNAME\", true),\n            DiktatError(3, 23, ruleId, \"${CLASS_NAME_INCORRECT.warnText()} IncorrectNAME\", true)\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.CONSTANT_UPPERCASE)\n    fun `number in middle name`() {\n        lintMethod(\n            \"\"\"\n                    const val NE04J_STARTUP_DELAY_MILLIS = 200L\n            \"\"\".trimIndent()\n        )\n    }\n\n    @Test\n    @Tags(\n        Tag(WarningNames.CLASS_NAME_INCORRECT),\n        Tag(WarningNames.VARIABLE_NAME_INCORRECT_FORMAT),\n        Tag(WarningNames.CONSTANT_UPPERCASE)\n    )\n    fun `check identifiers case format (check - negative)`() {\n        val code =\n            \"\"\"\n              var SOMEtest = \"TEST\"\n              const val thisConstantShouldBeUpper = \"CONST\"\n              class className {\n                  data class badClassName(val FIRST: String, var SECOND: String)\n\n                  companion object {\n                      const val incorrect_case = \"\"\n                      val correctCase = \"\"\n                      var INCORRECT = \"\"\n                  }\n\n                  var check_me = \"\"\n                  val CHECK_ME = \"\"\n              }\n            \"\"\".trimIndent()\n\n        lintMethod(code,\n            DiktatError(1, 5, ruleId, \"${VARIABLE_NAME_INCORRECT_FORMAT.warnText()} SOMEtest\", false),\n            DiktatError(2, 11, ruleId, \"${CONSTANT_UPPERCASE.warnText()} thisConstantShouldBeUpper\", false),\n            DiktatError(3, 7, ruleId, \"${CLASS_NAME_INCORRECT.warnText()} className\", true),\n            DiktatError(4, 16, ruleId, \"${CLASS_NAME_INCORRECT.warnText()} badClassName\", true),\n            DiktatError(4, 33, ruleId, \"${VARIABLE_NAME_INCORRECT_FORMAT.warnText()} FIRST\", false),\n            DiktatError(4, 52, ruleId, \"${VARIABLE_NAME_INCORRECT_FORMAT.warnText()} SECOND\", false),\n            DiktatError(7, 19, ruleId, \"${CONSTANT_UPPERCASE.warnText()} incorrect_case\", false),\n            DiktatError(9, 13, ruleId, \"${VARIABLE_NAME_INCORRECT_FORMAT.warnText()} INCORRECT\", false),\n            DiktatError(12, 9, ruleId, \"${VARIABLE_NAME_INCORRECT_FORMAT.warnText()} check_me\", false),\n            DiktatError(13, 9, ruleId, \"${VARIABLE_NAME_INCORRECT_FORMAT.warnText()} CHECK_ME\", false)\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.CONSTANT_UPPERCASE)\n    fun `serialVersionUID should be ignored`() {\n        lintMethod(\n            \"\"\"\n                class TestSerializableClass() : Serializable {\n                    companion object {\n                        private const val serialVersionUID: Long = -1\n                    }\n                }\n            \"\"\".trimIndent(),\n            rulesConfigList = rulesConfigConstantUpperCase\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.CONSTANT_UPPERCASE)\n    fun `should trigger when the name is not exception`() {\n        val code =\n            \"\"\"\n                class TestSerializableClass() : Serializable {\n                    companion object {\n                        private const val serialVersion: Long = -1\n                    }\n                }\n            \"\"\".trimIndent()\n        lintMethod(code,\n            DiktatError(3, 27, ruleId, \"${CONSTANT_UPPERCASE.warnText()} serialVersion\", true)\n        )\n    }\n\n    @Test\n    @Tags(Tag(WarningNames.IDENTIFIER_LENGTH), Tag(WarningNames.VARIABLE_NAME_INCORRECT))\n    fun `check variable length (check - negative)`() {\n        val code =\n            \"\"\"\n                val r = 0\n                val x256 = 256\n                val i = 1\n                class LongLongLongLongLongLongLongLongLongLongLongLongLongLongLongLongLongName {\n                    val veryLongveryLongveryLongveryLongveryLongveryLongveryLongveryLongveryLongName =                \"                \"\n                }\n            \"\"\".trimIndent()\n        lintMethod(code,\n            DiktatError(1, 5, ruleId, \"${IDENTIFIER_LENGTH.warnText()} r\"),\n            DiktatError(2, 5, ruleId, \"${VARIABLE_NAME_INCORRECT.warnText()} x256\"),\n            DiktatError(4, 7, ruleId, \"${IDENTIFIER_LENGTH.warnText()} LongLongLongLongLongLongLongLongLongLongLongLongLongLongLongLongLongName\"),\n            DiktatError(5, 9, ruleId, \"${IDENTIFIER_LENGTH.warnText()} veryLongveryLongveryLongveryLongveryLongveryLongveryLongveryLongveryLongName\")\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.VARIABLE_NAME_INCORRECT_FORMAT)\n    fun `check value parameters in dataclasses (check - negative)`() {\n        val code =\n            \"\"\"\n                data class ClassName(val FIRST: String, var SECOND: String)\n            \"\"\".trimIndent()\n        lintMethod(code,\n            DiktatError(1, 26, ruleId, \"${VARIABLE_NAME_INCORRECT_FORMAT.warnText()} FIRST\", false),\n            DiktatError(1, 45, ruleId, \"${VARIABLE_NAME_INCORRECT_FORMAT.warnText()} SECOND\", false)\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.VARIABLE_NAME_INCORRECT_FORMAT)\n    fun `check value parameters in functions (check - negative)`() {\n        val code =\n            \"\"\"\n                fun foo(SOMENAME: String) {\n                }\n            \"\"\".trimIndent()\n        lintMethod(code,\n            DiktatError(1, 9, ruleId, \"${VARIABLE_NAME_INCORRECT_FORMAT.warnText()} SOMENAME\", true)\n        )\n    }\n\n    @Test\n    @Tags(Tag(WarningNames.ENUM_VALUE), Tag(WarningNames.CLASS_NAME_INCORRECT))\n    fun `check case for enum values (check - negative)`() {\n        val code =\n            \"\"\"\n                enum class TEST_ONE {\n                    first_value, secondValue, thirdVALUE, FourthValue\n                }\n            \"\"\".trimIndent()\n        lintMethod(code,\n            DiktatError(1, 12, ruleId, \"${CLASS_NAME_INCORRECT.warnText()} TEST_ONE\", true),\n            DiktatError(2, 5, ruleId, \"${ENUM_VALUE.warnText()} first_value (should be in UPPER_SNAKE_CASE)\", true),\n            DiktatError(2, 18, ruleId, \"${ENUM_VALUE.warnText()} secondValue (should be in UPPER_SNAKE_CASE)\", true),\n            DiktatError(2, 31, ruleId, \"${ENUM_VALUE.warnText()} thirdVALUE (should be in UPPER_SNAKE_CASE)\", true),\n            DiktatError(2, 43, ruleId, \"${ENUM_VALUE.warnText()} FourthValue (should be in UPPER_SNAKE_CASE)\", true)\n        )\n    }\n\n    @Test\n    @Tags(Tag(WarningNames.ENUM_VALUE), Tag(WarningNames.CLASS_NAME_INCORRECT))\n    fun `check case for pascal case enum values (check - negative)`() {\n        val rulesConfigPascalCaseEnum: List<RulesConfig> = listOf(\n            RulesConfig(ENUM_VALUE.name, true,\n                mapOf(\"enumStyle\" to \"pascalCase\"))\n        )\n        val code =\n            \"\"\"\n                enum class TEST_ONE {\n                    first_value, secondValue, thirdVALUE, FOURTH_VALUE\n                }\n            \"\"\".trimIndent()\n        lintMethod(code,\n            DiktatError(1, 12, ruleId, \"${CLASS_NAME_INCORRECT.warnText()} TEST_ONE\", true),\n            DiktatError(2, 5, ruleId, \"${ENUM_VALUE.warnText()} first_value (should be in PascalCase)\", true),\n            DiktatError(2, 18, ruleId, \"${ENUM_VALUE.warnText()} secondValue (should be in PascalCase)\", true),\n            DiktatError(2, 31, ruleId, \"${ENUM_VALUE.warnText()} thirdVALUE (should be in PascalCase)\", true),\n            DiktatError(2, 43, ruleId, \"${ENUM_VALUE.warnText()} FOURTH_VALUE (should be in PascalCase)\", true),\n            rulesConfigList = rulesConfigPascalCaseEnum\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.OBJECT_NAME_INCORRECT)\n    fun `check case for object (check - negative)`() {\n        val code =\n            \"\"\"\n                object TEST_ONE {\n                }\n            \"\"\".trimIndent()\n        lintMethod(code,\n            DiktatError(1, 8, ruleId, \"${OBJECT_NAME_INCORRECT.warnText()} TEST_ONE\", true)\n        )\n    }\n\n    // ======== exception case and suffix ========\n    @Test\n    @Tag(WarningNames.CLASS_NAME_INCORRECT)\n    fun `check exception case format`() {\n        val code =\n            \"\"\"\n                class incorrect_case_Exception(message: String) : Exception(message)\n            \"\"\".trimIndent()\n        lintMethod(code,\n            DiktatError(1, 7, ruleId, \"${CLASS_NAME_INCORRECT.warnText()} incorrect_case_Exception\", true)\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.EXCEPTION_SUFFIX)\n    fun `check exception case and suffix (with type call entry) - negative`() {\n        val code =\n            \"\"\"\n                class Custom(message: String) : Exception(message)\n            \"\"\".trimIndent()\n        lintMethod(code,\n            DiktatError(1, 7, ruleId, \"${EXCEPTION_SUFFIX.warnText()} Custom\", true)\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.EXCEPTION_SUFFIX)\n    fun `check exception case and suffix (only parent name inheritance) - negative`() {\n        val code =\n            \"\"\"\n                class Custom: Exception {\n                    constructor(msg: String) : super(msg)\n                }\n            \"\"\".trimIndent()\n        lintMethod(code,\n            DiktatError(1, 7, ruleId, \"${EXCEPTION_SUFFIX.warnText()} Custom\", true)\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.VARIABLE_HAS_PREFIX)\n    fun `checking that there should be no prefixes in variable name`() {\n        val code =\n            \"\"\"\n                const val M_GLOB = \"\"\n                val aPrefix = \"\"\n            \"\"\".trimIndent()\n        lintMethod(code,\n            DiktatError(1, 11, ruleId, \"${VARIABLE_HAS_PREFIX.warnText()} M_GLOB\", true),\n            DiktatError(2, 5, ruleId, \"${VARIABLE_HAS_PREFIX.warnText()} aPrefix\", true)\n        )\n    }\n\n    @Test\n    @Tags(Tag(WarningNames.VARIABLE_NAME_INCORRECT_FORMAT), Tag(WarningNames.VARIABLE_HAS_PREFIX))\n    fun `regression - checking that digit in the end will not raise a warning`() {\n        val code =\n            \"\"\"\n                val I_AM_CONSTANT1  = \"\"\n                const val I_AM_CONSTANT2  = \"\"\n            \"\"\".trimIndent()\n        lintMethod(code,\n            DiktatError(1, 5, ruleId, \"${VARIABLE_NAME_INCORRECT_FORMAT.warnText()} I_AM_CONSTANT1\", false),\n            DiktatError(1, 5, ruleId, \"${VARIABLE_HAS_PREFIX.warnText()} I_AM_CONSTANT1\", true),\n            DiktatError(2, 11, ruleId, \"${VARIABLE_HAS_PREFIX.warnText()} I_AM_CONSTANT2\", true)\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.VARIABLE_NAME_INCORRECT_FORMAT)\n    fun `regression - destructing declaration in lambdas - incorrect case `() {\n        val code =\n            \"\"\"\n                private fun checkCommentedCode(node: ASTNode) {\n                    val eolCommentsOffsetToText = \"\"\n                    val blockCommentsOffsetToText = \"\"\n                    (eolCommentsOffsetToText + blockCommentsOffsetToText)\n                    .map { (STRANGECASE, text) ->\n                        \"\"\n                    }\n                }\n            \"\"\".trimIndent()\n        lintMethod(code,\n            DiktatError(5, 13, ruleId, \"${VARIABLE_NAME_INCORRECT_FORMAT.warnText()} STRANGECASE\", true)\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.VARIABLE_NAME_INCORRECT_FORMAT)\n    fun `regression - lambda argument - incorrect case`() {\n        val code =\n            \"\"\"\n                private fun checkCommentedCode(node: ASTNode) {\n                    val eolCommentsOffsetToText = \"\"\n                    eolCommentsOffsetToText.map { STRANGECASE ->\n                        \"\"\n                    }\n                }\n            \"\"\".trimIndent()\n        lintMethod(code,\n            DiktatError(3, 35, ruleId, \"${VARIABLE_NAME_INCORRECT_FORMAT.warnText()} STRANGECASE\", true)\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.FUNCTION_BOOLEAN_PREFIX)\n    fun `FUNCTION_BOOLEAN_PREFIX - positive example`() {\n        lintMethod(\n            \"\"\"\n                    fun ASTNode.hasEmptyLineAfter(): Boolean { }\n                    fun hasEmptyLineAfter(): Boolean { }\n                    fun ASTNode.isEmpty(): Boolean { }\n                    fun isEmpty(): Boolean { }\n                    override fun empty(): Boolean { }\n                    override fun ASTNode.empty(): Boolean { }\n            \"\"\".trimIndent()\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.FUNCTION_BOOLEAN_PREFIX)\n    fun `FUNCTION_BOOLEAN_PREFIX - negative example`() {\n        lintMethod(\n            \"\"\"\n                    fun ASTNode.emptyLineAfter(): Boolean { }\n                    fun emptyLineAfter(): Boolean { }\n                    fun ASTNode.empty(): Boolean { }\n                    fun empty(): Boolean { }\n            \"\"\".trimIndent(),\n            DiktatError(1, 13, ruleId, \"${FUNCTION_BOOLEAN_PREFIX.warnText()} emptyLineAfter\", false),\n            DiktatError(2, 5, ruleId, \"${FUNCTION_BOOLEAN_PREFIX.warnText()} emptyLineAfter\", false),\n            DiktatError(3, 13, ruleId, \"${FUNCTION_BOOLEAN_PREFIX.warnText()} empty\", false),\n            DiktatError(4, 5, ruleId, \"${FUNCTION_BOOLEAN_PREFIX.warnText()} empty\", false)\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.FUNCTION_BOOLEAN_PREFIX)\n    fun `all prefixes for boolean methods`() {\n        lintMethod(\n            \"\"\"\n                    fun hasEmptyLineAfter(): Boolean { }\n                    fun haveEmptyLineAfter(): Boolean { }\n                    fun isEmpty(): Boolean { }\n                    fun shouldBeEmpty(): Boolean { }\n                    fun areEmpty(): Boolean { }\n            \"\"\".trimIndent()\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.FUNCTION_BOOLEAN_PREFIX)\n    fun `test allowed boolean functions in configuration`() {\n        lintMethod(\n            \"\"\"\n                    fun equalsSome(): Boolean { }\n                    fun fooBar(): Boolean { }\n                    fun equivalentToAnother(): Boolean { }\n            \"\"\".trimIndent(),\n            rulesConfigList = rulesConfigBooleanFunctions\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.FUNCTION_BOOLEAN_PREFIX)\n    fun `fixed false positive result on operator functions`() {\n        lintMethod(\n            \"\"\"\n                    inline operator fun component3(): Boolean = asDynamic()[2].unsafeCast<Boolean>()\n            \"\"\".trimIndent()\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.IDENTIFIER_LENGTH)\n    fun `regression - function argument type`() {\n        // valid example, should not cause exceptions\n        lintMethod(\n            \"\"\"\n                    fun foo(predicate: (Int) -> Boolean) = Unit\n            \"\"\".trimIndent()\n        )\n\n        // identifier names in function types are still checked if present\n        lintMethod(\n            \"\"\"\n                    fun foo(predicate: (a: Int) -> Boolean) = Unit\n            \"\"\".trimIndent(),\n            DiktatError(1, 21, ruleId, \"${IDENTIFIER_LENGTH.warnText()} a\", false)\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.IDENTIFIER_LENGTH)\n    fun `regression - object parsing should not fail with anonymous objects`() {\n        val code =\n            \"\"\"\n                val fakeVal = RuleSet(\"test\", object : Rule(\"astnode-utils-test\") {\n                                override fun visit(node: ASTNode) {}\n                                })\n            \"\"\".trimIndent()\n        lintMethod(code)\n    }\n\n    @Test\n    @Tag(WarningNames.IDENTIFIER_LENGTH)\n    fun `exception case for identifier naming in catch statements`() {\n        val code =\n            \"\"\"\n                fun foo() {\n                    try {\n                    } catch (e: IOException) {\n                    }\n                }\n            \"\"\".trimIndent()\n        lintMethod(code)\n    }\n\n    @Test\n    @Tag(WarningNames.IDENTIFIER_LENGTH)\n    fun `exception case for identifier naming in catch statements with catch body`() {\n        val code =\n            \"\"\"\n                fun foo() {\n                    try {\n                    } catch (e: IOException) {\n                        fun foo(e: Int) {\n                        }\n                    }\n                }\n            \"\"\".trimIndent()\n        lintMethod(code, DiktatError(4, 17, ruleId, \"${IDENTIFIER_LENGTH.warnText()} e\", false))\n    }\n\n    @Test\n    @Tag(WarningNames.IDENTIFIER_LENGTH)\n    fun `exception case for identifier naming - catching exception with type e`() {\n        val code =\n            \"\"\"\n                fun foo() {\n                    try {\n                    } catch (e: e) {\n                    }\n                }\n            \"\"\".trimIndent()\n        lintMethod(code)\n    }\n\n    @Test\n    @Tag(WarningNames.BACKTICKS_PROHIBITED)\n    fun `backticks should be used only with functions from tests (function)`() {\n        val code =\n            \"\"\"\n                fun `foo function`(`argument with backstick`: String) {\n                    val `foo variable` = \"\"\n                }\n            \"\"\".trimIndent()\n        lintMethod(code,\n            DiktatError(1, 5, ruleId, \"${BACKTICKS_PROHIBITED.warnText()} `foo function`\"),\n            DiktatError(1, 20, ruleId, \"${BACKTICKS_PROHIBITED.warnText()} `argument with backstick`\"),\n            DiktatError(2, 9, ruleId, \"${BACKTICKS_PROHIBITED.warnText()} `foo variable`\")\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.BACKTICKS_PROHIBITED)\n    fun `backticks should be used only with functions from tests (test method)`() {\n        val code =\n            \"\"\"\n                @Test\n                fun `test function with backstick`() {\n                }\n            \"\"\".trimIndent()\n        lintMethod(code)\n    }\n\n    @Test\n    @Tag(WarningNames.BACKTICKS_PROHIBITED)\n    fun `backticks should be used only with functions from tests (test method with variables)`() {\n        val code =\n            \"\"\"\n                @Test\n                fun `test function with backstick`() {\n                    val `should not be used` = \"\"\n\n                }\n            \"\"\".trimIndent()\n        lintMethod(code, DiktatError(3, 9, ruleId, \"${BACKTICKS_PROHIBITED.warnText()} `should not be used`\"))\n    }\n\n    @Test\n    @Tag(WarningNames.BACKTICKS_PROHIBITED)\n    fun `backticks should be used only with functions from tests (class)`() {\n        val code =\n            \"\"\"\n                class `my class name` {}\n            \"\"\".trimIndent()\n        lintMethod(code, DiktatError(1, 7, ruleId, \"${BACKTICKS_PROHIBITED.warnText()} `my class name`\"))\n    }\n\n    @Test\n    @Tag(WarningNames.BACKTICKS_PROHIBITED)\n    fun `regression - backticks should be forbidden only in declarations`() {\n        lintMethod(\n            \"\"\"\n                |fun foo() {\n                |    it.assertThat(actual.detail).`as`(\"Detailed message\").isEqualTo(expected.detail)\n                |}\n            \"\"\".trimMargin()\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.VARIABLE_NAME_INCORRECT_FORMAT)\n    fun `should not trigger on underscore`() {\n        val code =\n            \"\"\"\n                class SomeClass {\n                    fun bar() {\n                        val ast = list.map {(first, _) -> foo(first)}\n\n                        var meanValue: Int = 0\n                            for ((\n                                _,\n                                _,\n                                year\n                            ) in cars) {\n                                meanValue += year\n                            }\n\n                        try {\n                            /* ... */\n                        } catch (_: IOException) {\n                            /* ... */\n                        }\n                    }\n                }\n            \"\"\".trimIndent()\n        lintMethod(code)\n    }\n\n    @Test\n    @Tag(WarningNames.VARIABLE_NAME_INCORRECT_FORMAT)\n    fun `should not trigger on backing field`() {\n        lintMethod(\n            \"\"\"\n                    |package com.example\n                    |\n                    |class MutableTableContainer {\n                    |   private var _table: Map<String, Int>? = null\n                    |\n                    |   val table: Map<String, Int>\n                    |       get() {\n                    |           if (_table == null) {\n                    |               _table = hashMapOf()\n                    |           }\n                    |           return _table ?: throw AssertionError(\"Set to null by another thread\")\n                    |       }\n                    |       set(value) {\n                    |           field = value\n                    |       }\n                    |\n                    |}\n            \"\"\".trimMargin(),\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.VARIABLE_NAME_INCORRECT_FORMAT)\n    fun `should trigger on backing field with setter`() {\n        val code =\n            \"\"\"\n                    |package com.example\n                    |\n                    |class MutableTableContainer {\n                    |   private var _table: Map<String, Int>? = null\n                    |                set(value) {\n                    |                    field = value\n                    |                }\n                    |\n                    |   val table: Map<String, Int>\n                    |       get() {\n                    |           if (_table == null) {\n                    |               _table = hashMapOf()\n                    |           }\n                    |           return _table ?: throw AssertionError(\"Set to null by another thread\")\n                    |       }\n                    |       set(value) {\n                    |           field = value\n                    |       }\n                    |\n                    |}\n            \"\"\".trimMargin()\n        lintMethod(code,\n            DiktatError(4, 16, ruleId, \"${VARIABLE_NAME_INCORRECT_FORMAT.warnText()} _table\", true),\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.VARIABLE_NAME_INCORRECT_FORMAT)\n    fun `should trigger on backing field with no matching property`() {\n        val code =\n            \"\"\"\n                    |package com.example\n                    |\n                    |class MutableTableContainer {\n                    |   private var __table: Map<String, Int>? = null\n                    |\n                    |   val table: Map<String, Int>\n                    |       get() {\n                    |           if (_table == null) {\n                    |               _table = hashMapOf()\n                    |           }\n                    |           return _table ?: throw AssertionError(\"Set to null by another thread\")\n                    |       }\n                    |       set(value) {\n                    |           field = value\n                    |       }\n                    |\n                    |}\n            \"\"\".trimMargin()\n        lintMethod(code,\n            DiktatError(4, 16, ruleId, \"${VARIABLE_NAME_INCORRECT_FORMAT.warnText()} __table\", true),\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.VARIABLE_NAME_INCORRECT_FORMAT)\n    fun `should trigger on backing field with unmatched type`() {\n        val code =\n            \"\"\"\n                    |package com.example\n                    |\n                    |class MutableTableContainer {\n                    |   private var _table: Map<String, Double>? = null\n                    |\n                    |   val table: Map<String, Int>\n                    |       get() {\n                    |           if (_table == null) {\n                    |               _table = hashMapOf()\n                    |           }\n                    |           return _table ?: throw AssertionError(\"Set to null by another thread\")\n                    |       }\n                    |       set(value) {\n                    |           field = value\n                    |       }\n                    |\n                    |}\n            \"\"\".trimMargin()\n        lintMethod(code,\n            DiktatError(4, 16, ruleId, \"${VARIABLE_NAME_INCORRECT_FORMAT.warnText()} _table\", true),\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.CONFUSING_IDENTIFIER_NAMING)\n    fun `confusing identifier naming`() {\n        val code =\n            \"\"\"\n                fun someFunc() {\n                    val D = 0\n                    val Z = 2\n                }\n\n                enum class Ident {\n                    B\n                }\n            \"\"\".trimIndent()\n        lintMethod(code,\n            DiktatError(2, 9, ruleId, \"${CONFUSING_IDENTIFIER_NAMING.warnText()} better name is: obj, dgt\", false),\n            DiktatError(2, 9, ruleId, \"${VARIABLE_NAME_INCORRECT_FORMAT.warnText()} D\", true),\n            DiktatError(2, 9, ruleId, \"${IDENTIFIER_LENGTH.warnText()} D\", false),\n            DiktatError(3, 9, ruleId, \"${CONFUSING_IDENTIFIER_NAMING.warnText()} better name is: n1, n2\", false),\n            DiktatError(3, 9, ruleId, \"${VARIABLE_NAME_INCORRECT_FORMAT.warnText()} Z\", true),\n            DiktatError(3, 9, ruleId, \"${IDENTIFIER_LENGTH.warnText()} Z\", false),\n            DiktatError(7, 5, ruleId, \"${CONFUSING_IDENTIFIER_NAMING.warnText()} better name is: bt, nxt\", false),\n            DiktatError(7, 5, ruleId, \"${IDENTIFIER_LENGTH.warnText()} B\", false))\n    }\n\n    @Test\n    @Tag(WarningNames.GENERIC_NAME)\n    fun `check generic types`() {\n        val code =\n            \"\"\"\n                interface Test<String>\n                interface Test1<T: String>\n                interface Test2<T : Collection<T>>\n                interface Test3<out T>\n                interface Test3<in T>\n                interface Test4<in T, A, B>\n                interface Test5<in T, A, Br>\n                interface Test6<in Tr>\n                interface Test6<Tr: String>\n            \"\"\".trimIndent()\n        lintMethod(code,\n            DiktatError(1, 15, ruleId, \"${GENERIC_NAME.warnText()} <String>\", false),\n            DiktatError(7, 16, ruleId, \"${GENERIC_NAME.warnText()} <in T, A, Br>\", false),\n            DiktatError(8, 16, ruleId, \"${GENERIC_NAME.warnText()} <in Tr>\", false),\n            DiktatError(9, 16, ruleId, \"${GENERIC_NAME.warnText()} <Tr: String>\", false),\n        )\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/test/kotlin/com/saveourtool/diktat/ruleset/chapter1/MethodNamingWarnTest.kt",
    "content": "package com.saveourtool.diktat.ruleset.chapter1\n\nimport com.saveourtool.diktat.common.config.rules.DIKTAT_RULE_SET_ID\nimport com.saveourtool.diktat.ruleset.constants.Warnings.FUNCTION_BOOLEAN_PREFIX\nimport com.saveourtool.diktat.ruleset.constants.Warnings.FUNCTION_NAME_INCORRECT_CASE\nimport com.saveourtool.diktat.ruleset.constants.Warnings.TYPEALIAS_NAME_INCORRECT_CASE\nimport com.saveourtool.diktat.ruleset.rules.chapter1.IdentifierNaming\nimport com.saveourtool.diktat.util.LintTestBase\n\nimport com.saveourtool.diktat.api.DiktatError\nimport generated.WarningNames\nimport org.junit.jupiter.api.Tag\nimport org.junit.jupiter.api.Test\n\nclass MethodNamingWarnTest : LintTestBase(::IdentifierNaming) {\n    private val ruleId: String = \"$DIKTAT_RULE_SET_ID:${IdentifierNaming.NAME_ID}\"\n\n    @Test\n    @Tag(WarningNames.FUNCTION_NAME_INCORRECT_CASE)\n    fun `method name incorrect, part 1`() {\n        val code =\n            \"\"\"\n                class SomeClass {\n                    fun /* */ methODTREE(): String {\n\n                    }\n                }\n            \"\"\".trimIndent()\n        lintMethod(code, DiktatError(2, 15, ruleId, \"${FUNCTION_NAME_INCORRECT_CASE.warnText()} methODTREE\", true))\n    }\n\n    @Test\n    @Tag(WarningNames.FUNCTION_NAME_INCORRECT_CASE)\n    fun `method name incorrect, part 2`() {\n        val code =\n            \"\"\"\n                class TestPackageName {\n                    fun method_two(): String {\n                        return \"\"\n                    }\n                }\n            \"\"\".trimIndent()\n        lintMethod(code, DiktatError(2, 9, ruleId, \"${FUNCTION_NAME_INCORRECT_CASE.warnText()} method_two\", true))\n    }\n\n    @Test\n    @Tag(WarningNames.FUNCTION_NAME_INCORRECT_CASE)\n    fun `method name incorrect, part 3`() {\n        val code =\n            \"\"\"\n                fun String.methODTREE(): String {\n                    fun TEST(): Unit {\n                        return \"\"\n                    }\n                }\n            \"\"\".trimIndent()\n        lintMethod(code,\n            DiktatError(1, 12, ruleId, \"${FUNCTION_NAME_INCORRECT_CASE.warnText()} methODTREE\", true),\n            DiktatError(2, 9, ruleId, \"${FUNCTION_NAME_INCORRECT_CASE.warnText()} TEST\", true)\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.FUNCTION_NAME_INCORRECT_CASE)\n    fun `method name incorrect, part 4`() {\n        val code =\n            \"\"\"\n                class TestPackageName {\n                    fun methODTREE(): String {\n                    }\n                }\n            \"\"\".trimIndent()\n        lintMethod(code, DiktatError(2, 9, ruleId, \"${FUNCTION_NAME_INCORRECT_CASE.warnText()} methODTREE\", true))\n    }\n\n    @Test\n    @Tag(WarningNames.FUNCTION_NAME_INCORRECT_CASE)\n    fun `method name incorrect, part 5`() {\n        val code =\n            \"\"\"\n                class TestPackageName {\n                    fun methODTREE() {\n                    }\n                }\n            \"\"\".trimIndent()\n        lintMethod(code, DiktatError(2, 9, ruleId, \"${FUNCTION_NAME_INCORRECT_CASE.warnText()} methODTREE\", true))\n    }\n\n    @Test\n    @Tag(WarningNames.TYPEALIAS_NAME_INCORRECT_CASE)\n    fun `typeAlias name incorrect, part 1`() {\n        val code =\n            \"\"\"\n                class TestPackageName {\n                    typealias relatedClasses = List<Pair<String, String>>\n                }\n            \"\"\".trimIndent()\n        lintMethod(code, DiktatError(2, 15, ruleId, \"${TYPEALIAS_NAME_INCORRECT_CASE.warnText()} relatedClasses\", true))\n    }\n\n    @Test\n    @Tag(WarningNames.TYPEALIAS_NAME_INCORRECT_CASE)\n    fun `typeAlias name incorrect, part 2`() {\n        lintMethod(\n            \"\"\"\n                  class TestPackageName {\n                    typealias RelatedClasses = List<Pair<String, String>>\n                  }\n            \"\"\".trimIndent()\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.FUNCTION_BOOLEAN_PREFIX)\n    fun `boolean method name incorrect`() {\n        val code =\n            \"\"\"\n                fun someBooleanCheck(): Boolean {\n                    return false\n                }\n            \"\"\".trimIndent()\n        lintMethod(code, DiktatError(1, 5, ruleId, \"${FUNCTION_BOOLEAN_PREFIX.warnText()} someBooleanCheck\", false))\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/test/kotlin/com/saveourtool/diktat/ruleset/chapter1/PackageNamingFixTest.kt",
    "content": "package com.saveourtool.diktat.ruleset.chapter1\n\nimport com.saveourtool.diktat.common.config.rules.RulesConfig\nimport com.saveourtool.diktat.ruleset.rules.chapter1.PackageNaming\nimport com.saveourtool.diktat.util.FixTestBase\n\nimport generated.WarningNames\nimport org.junit.jupiter.api.Tag\nimport org.junit.jupiter.api.Test\n\nclass PackageNamingFixTest : FixTestBase(\n    \"test/paragraph1/naming/package\",\n    ::PackageNaming,\n    listOf(RulesConfig(\"DIKTAT_COMMON\", true, mapOf(\"domainName\" to \"com.saveourtool.diktat\")))\n) {\n    @Test\n    @Tag(WarningNames.PACKAGE_NAME_INCORRECT_CASE)\n    fun `incorrect case of package name (fix)`() {\n        fixAndCompare(\"FixUpperExpected.kt\", \"FixUpperTest.kt\")\n    }\n\n    @Test\n    @Tag(WarningNames.PACKAGE_NAME_INCORRECT_PATH)\n    fun `fixing incorrect domain name (fix)`() {\n        fixAndCompare(\"MissingDomainNameExpected.kt\", \"MissingDomainNameTest.kt\")\n    }\n\n    @Test\n    @Tag(WarningNames.INCORRECT_PACKAGE_SEPARATOR)\n    fun `incorrect usage of package separator (fix)`() {\n        fixAndCompare(\"FixUnderscoreExpected.kt\", \"FixUnderscoreTest.kt\")\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/test/kotlin/com/saveourtool/diktat/ruleset/chapter1/PackageNamingWarnTest.kt",
    "content": "package com.saveourtool.diktat.ruleset.chapter1\n\nimport com.saveourtool.diktat.common.config.rules.DIKTAT_RULE_SET_ID\nimport com.saveourtool.diktat.common.config.rules.RulesConfig\nimport com.saveourtool.diktat.ruleset.constants.Warnings.INCORRECT_PACKAGE_SEPARATOR\nimport com.saveourtool.diktat.ruleset.constants.Warnings.PACKAGE_NAME_INCORRECT_CASE\nimport com.saveourtool.diktat.ruleset.constants.Warnings.PACKAGE_NAME_INCORRECT_PATH\nimport com.saveourtool.diktat.ruleset.constants.Warnings.PACKAGE_NAME_INCORRECT_PREFIX\nimport com.saveourtool.diktat.ruleset.constants.Warnings.PACKAGE_NAME_INCORRECT_SYMBOLS\nimport com.saveourtool.diktat.ruleset.constants.Warnings.PACKAGE_NAME_MISSING\nimport com.saveourtool.diktat.ruleset.rules.chapter1.PackageNaming\nimport com.saveourtool.diktat.util.LintTestBase\nimport com.saveourtool.diktat.util.TEST_FILE_NAME\n\nimport com.saveourtool.diktat.api.DiktatError\nimport generated.WarningNames\nimport org.junit.jupiter.api.Tag\nimport org.junit.jupiter.api.Test\nimport org.junit.jupiter.api.io.TempDir\nimport java.nio.file.Path\n\nclass PackageNamingWarnTest : LintTestBase(::PackageNaming) {\n    private val ruleId: String = \"$DIKTAT_RULE_SET_ID:${PackageNaming.NAME_ID}\"\n    private val rulesConfigList: List<RulesConfig> = listOf(\n        RulesConfig(\"DIKTAT_COMMON\", true, mapOf(\"domainName\" to \"com.saveourtool.diktat\"))\n    )\n    private val rulesConfigListEmptyDomainName: List<RulesConfig> = listOf(\n        RulesConfig(\"DIKTAT_COMMON\", true, mapOf(\"domainName\" to \"\"))\n    )\n    private val rulesConfigSourceDirectories: List<RulesConfig> = listOf(\n        RulesConfig(\"DIKTAT_COMMON\", true, mapOf(\n            \"domainName\" to \"com.saveourtool.diktat\",\n            \"srcDirectories\" to \"nativeMain, mobileMain\",\n            \"testDirs\" to \"nativeTest\"\n        ))\n    )\n\n    @Test\n    @Tag(WarningNames.PACKAGE_NAME_MISSING)\n    fun `missing package name (check)`(@TempDir tempDir: Path) {\n        lintMethodWithFile(\n            \"\"\"\n                import com.saveourtool.diktat.a.b.c\n\n                /**\n                 * testComment\n                 */\n                class TestPackageName {  }\n\n            \"\"\".trimIndent(),\n            tempDir = tempDir,\n            fileName = TEST_FILE_NAME,\n            DiktatError(1, 1, ruleId, \"${PACKAGE_NAME_MISSING.warnText()} $TEST_FILE_NAME\", true),\n            rulesConfigList = rulesConfigList\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.PACKAGE_NAME_MISSING)\n    fun `missing package name with annotation (check)`(@TempDir tempDir: Path) {\n        lintMethodWithFile(\n            \"\"\"\n                @file:Suppress(\"CONSTANT_UPPERCASE\")\n\n                import com.saveourtool.diktat.a.b.c\n\n                /**\n                 * testComment\n                 */\n                class TestPackageName {  }\n\n            \"\"\".trimIndent(),\n            tempDir = tempDir,\n            fileName = TEST_FILE_NAME,\n            DiktatError(1, 37, ruleId, \"${PACKAGE_NAME_MISSING.warnText()} $TEST_FILE_NAME\", true),\n            rulesConfigList = rulesConfigList\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.PACKAGE_NAME_MISSING)\n    fun `don't add the package name to the file in buildSrc path`(@TempDir tempDir: Path) {\n        lintMethodWithFile(\n            \"\"\"\n                import com.saveourtool.diktat.a.b.c\n\n                /**\n                 * testComment\n                 */\n                class TestPackageName {  }\n\n            \"\"\".trimIndent(),\n            tempDir = tempDir,\n            fileName = \"diktat/buildSrc/src/main/kotlin/Version.kt\",\n            rulesConfigList = rulesConfigList\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.PACKAGE_NAME_INCORRECT_CASE)\n    fun `package name should be in a lower case (check)`() {\n        lintMethod(\n            \"\"\"\n                package /* AAA */ com.saveourtool.diktat.SPECIALTEST.test\n\n                import com.saveourtool.diktat.a.b.c\n\n                /**\n                 * testComment\n                 */\n                class TestPackageName {  }\n\n            \"\"\".trimIndent(),\n            DiktatError(1, 42, ruleId, \"${PACKAGE_NAME_INCORRECT_CASE.warnText()} SPECIALTEST\", true),\n            rulesConfigList = rulesConfigList\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.PACKAGE_NAME_INCORRECT_PREFIX)\n    fun `package name should start from domain name (check)`() {\n        lintMethod(\n\n            \"\"\"\n                package some.incorrect.domain.test\n\n                import com.saveourtool.diktat.a.b.c\n\n                /**\n                 * testComment\n                 */\n                class TestPackageName {  }\n\n            \"\"\".trimIndent(),\n            DiktatError(1, 9, ruleId, \"${PACKAGE_NAME_INCORRECT_PREFIX.warnText()} com.saveourtool.diktat\", true),\n            rulesConfigList = rulesConfigList\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.INCORRECT_PACKAGE_SEPARATOR)\n    fun `underscore exceptions - incorrect underscore case`() {\n        lintMethod(\n\n            \"\"\"\n                package com.saveourtool.diktat.domain.test_\n\n                import com.saveourtool.diktat.a.b.c\n\n                /**\n                 * testComment\n                 */\n                class TestPackageName {  }\n\n            \"\"\".trimIndent(),\n            DiktatError(1, 39, ruleId, \"${INCORRECT_PACKAGE_SEPARATOR.warnText()} test_\", true),\n            rulesConfigList = rulesConfigList\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.PACKAGE_NAME_INCORRECT_SYMBOLS)\n    fun `incorrect symbol in package name`() {\n        lintMethod(\n\n            \"\"\"\n                package com.saveourtool.diktat.domain.testш\n\n                import com.saveourtool.diktat.a.b.c\n\n                /**\n                 * testComment\n                 */\n                class TestPackageName {  }\n\n            \"\"\".trimIndent(),\n            DiktatError(1, 39, ruleId, \"${PACKAGE_NAME_INCORRECT_SYMBOLS.warnText()} testш\"),\n            rulesConfigList = rulesConfigList\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.PACKAGE_NAME_INCORRECT_SYMBOLS)\n    fun `underscore exceptions - positive case - keyword`() {\n        lintMethod(\n\n            \"\"\"\n                package com.saveourtool.diktat.domain.int_\n\n                import com.saveourtool.diktat.a.b.c\n\n                /**\n                 * testComment\n                 */\n                class TestPackageName {  }\n\n            \"\"\".trimIndent(),\n            rulesConfigList = rulesConfigList\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.PACKAGE_NAME_INCORRECT_SYMBOLS)\n    fun `test source config`(@TempDir tempDir: Path) {\n        lintMethodWithFile(\n\n            \"\"\"\n                package com.saveourtool.diktat.domain\n\n                import com.saveourtool.diktat.a.b.c\n\n                /**\n                 * testComment\n                 */\n                class TestPackageName {  }\n\n            \"\"\".trimIndent(),\n            tempDir = tempDir,\n            fileName = \"diktat/diktat-rules/src/nativeMain/kotlin/com/saveourtool/diktat/domain/BlaBla.kt\",\n            rulesConfigList = rulesConfigSourceDirectories\n        )\n\n        lintMethodWithFile(\n\n            \"\"\"\n                package com.saveourtool.diktat.domain\n\n                import com.saveourtool.diktat.a.b.c\n\n                /**\n                 * testComment\n                 */\n                class TestPackageName {  }\n\n            \"\"\".trimIndent(),\n            tempDir = tempDir,\n            fileName = \"diktat/diktat-rules/src/main/kotlin/com/saveourtool/diktat/domain/BlaBla.kt\",\n            DiktatError(1, 9, ruleId, \"${PACKAGE_NAME_INCORRECT_PATH.warnText()} com.saveourtool.diktat.main.kotlin.com.saveourtool.diktat.domain\", true),\n            rulesConfigList = rulesConfigSourceDirectories\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.PACKAGE_NAME_INCORRECT_SYMBOLS)\n    fun `test directories for test config`(@TempDir tempDir: Path) {\n        lintMethodWithFile(\n\n            \"\"\"\n                package com.saveourtool.diktat.domain\n\n                import com.saveourtool.diktat.a.b.c\n\n                /**\n                 * testComment\n                 */\n                class TestPackageName {  }\n\n            \"\"\".trimIndent(),\n            tempDir = tempDir,\n            fileName = \"diktat/diktat-rules/src/nativeTest/kotlin/com/saveourtool/diktat/domain/BlaBla.kt\",\n            rulesConfigList = rulesConfigSourceDirectories\n        )\n\n        lintMethodWithFile(\n\n            \"\"\"\n                package com.saveourtool.diktat.domain\n\n                import com.saveourtool.diktat.a.b.c\n\n                /**\n                 * testComment\n                 */\n                class TestPackageName {  }\n\n            \"\"\".trimIndent(),\n            tempDir = tempDir,\n            fileName = \"diktat/diktat-rules/src/test/kotlin/com/saveourtool/diktat/domain/BlaBla.kt\",\n            DiktatError(1, 9, ruleId, \"${PACKAGE_NAME_INCORRECT_PATH.warnText()} com.saveourtool.diktat.test.kotlin.com.saveourtool.diktat.domain\", true),\n            rulesConfigList = rulesConfigSourceDirectories\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.PACKAGE_NAME_INCORRECT_PATH)\n    fun `regression - incorrect warning on file under test directory`(@TempDir tempDir: Path) {\n        lintMethodWithFile(\n            \"\"\"\n                    package com.saveourtool.diktat.ruleset.chapter1\n            \"\"\".trimIndent(),\n            tempDir = tempDir,\n            fileName = \"diktat/diktat-rules/src/test/kotlin/com/saveourtool/diktat/ruleset/chapter1/EnumValueCaseTest.kt\",\n            rulesConfigList = rulesConfigList\n        )\n\n        lintMethodWithFile(\n            \"\"\"\n                    package com.saveourtool.diktat.chapter1\n            \"\"\".trimIndent(),\n            tempDir = tempDir,\n            fileName = \"diktat/diktat-rules/src/test/kotlin/com/saveourtool/diktat/ruleset/chapter1/EnumValueCaseTest.kt\",\n            DiktatError(1, 9, ruleId, \"${PACKAGE_NAME_INCORRECT_PATH.warnText()} com.saveourtool.diktat.ruleset.chapter1\", true),\n            rulesConfigList = rulesConfigList\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.PACKAGE_NAME_INCORRECT_PATH)\n    fun `regression - should not remove special words from file path`(@TempDir tempDir: Path) {\n        lintMethodWithFile(\n            \"\"\"\n                    |package com.saveourtool.diktat.test.processing\n            \"\"\".trimMargin(),\n            tempDir = tempDir,\n            fileName = \"project/module/src/test/kotlin/com/saveourtool/diktat/test/processing/SpecialPackageNaming.kt\",\n            rulesConfigList = rulesConfigList\n        )\n\n        lintMethodWithFile(\n            \"\"\"\n                    |package kotlin.collections\n            \"\"\".trimMargin(),\n            tempDir = tempDir,\n            fileName = \"project/module/src/main/kotlin/kotlin/collections/Collections.kt\",\n            rulesConfigList = listOf(\n                RulesConfig(\"DIKTAT_COMMON\", true, mapOf(\"domainName\" to \"kotlin\"))\n            )\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.PACKAGE_NAME_INCORRECT_PATH)\n    fun `should respect KMP project structure - positive example`(@TempDir tempDir: Path) {\n        listOf(\"main\", \"test\", \"jvmMain\", \"jvmTest\", \"androidMain\", \"androidTest\", \"iosMain\", \"iosTest\", \"jsMain\", \"jsTest\", \"commonMain\", \"commonTest\").forEach {\n            lintMethodWithFile(\n                \"\"\"\n                    |package com.saveourtool.diktat\n                \"\"\".trimMargin(),\n                tempDir = tempDir,\n                fileName = \"project/src/$it/kotlin/com/saveourtool/diktat/Example.kt\",\n                rulesConfigList = rulesConfigList\n            )\n        }\n    }\n\n    @Test\n    @Tag(WarningNames.PACKAGE_NAME_INCORRECT_PATH)\n    fun `should respect KMP project structure`(@TempDir tempDir: Path) {\n        listOf(\"main\", \"test\", \"jvmMain\", \"jvmTest\", \"androidMain\", \"androidTest\", \"iosMain\", \"iosTest\", \"jsMain\", \"jsTest\", \"commonMain\", \"commonTest\").forEach {\n            lintMethodWithFile(\n                \"\"\"\n                    |package com.saveourtool.diktat\n                \"\"\".trimMargin(),\n                tempDir = tempDir,\n                fileName = \"project/src/$it/kotlin/com/saveourtool/diktat/example/Example.kt\",\n                DiktatError(1, 9, ruleId, \"${PACKAGE_NAME_INCORRECT_PATH.warnText()} com.saveourtool.diktat.example\", true),\n                rulesConfigList = rulesConfigList\n            )\n        }\n    }\n\n    @Test\n    @Tag(WarningNames.PACKAGE_NAME_INCORRECT_PATH)\n    fun `should respect KMP project structure - illegal source set name`(@TempDir tempDir: Path) {\n        lintMethodWithFile(\n            \"\"\"\n                |package com.saveourtool.diktat\n            \"\"\".trimMargin(),\n            tempDir = tempDir,\n            fileName = \"project/src/myProjectMain/kotlin/com/saveourtool/diktat/example/Example.kt\",\n            DiktatError(1, 9, ruleId, \"${PACKAGE_NAME_INCORRECT_PATH.warnText()} com.saveourtool.diktat.myProjectMain.kotlin.com.saveourtool.diktat.example\", true),\n            rulesConfigList = rulesConfigList\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.PACKAGE_NAME_INCORRECT_PATH)\n    fun `should warn if there is empty domain name`(@TempDir tempDir: Path) {\n        lintMethodWithFile(\n            \"\"\"\n                |package com.saveourtool.diktat\n            \"\"\".trimMargin(),\n            tempDir = tempDir,\n            fileName = \"project/src/main/kotlin/com/saveourtool/diktat/example/Example.kt\",\n            DiktatError(1, 9, ruleId, \"${PACKAGE_NAME_INCORRECT_PREFIX.warnText()} \", true),\n            DiktatError(1, 9, ruleId, \"${PACKAGE_NAME_INCORRECT_PATH.warnText()} com.saveourtool.diktat.example\", true),\n            rulesConfigList = rulesConfigListEmptyDomainName\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.PACKAGE_NAME_INCORRECT_PATH)\n    fun `shouldn't trigger if path contains dot`(@TempDir tempDir: Path) {\n        lintMethodWithFile(\n            \"\"\"\n                |package com.saveourtool.diktat.test.utils\n            \"\"\".trimMargin(),\n            tempDir = tempDir,\n            fileName = \"project/src/main/kotlin/com/saveourtool/diktat/test.utils/Example.kt\",\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.PACKAGE_NAME_INCORRECT_PATH)\n    fun `shouldn't trigger for gradle script`(@TempDir tempDir: Path) {\n        lintMethodWithFile(\n            \"\"\"\n                |import com.saveourtool.diktat.generation.docs.generateAvailableRules\n            \"\"\".trimMargin(),\n            tempDir = tempDir,\n            fileName = \"project/build.gradle.kts\",\n        )\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/test/kotlin/com/saveourtool/diktat/ruleset/chapter1/PackagePathFixTest.kt",
    "content": "package com.saveourtool.diktat.ruleset.chapter1\n\nimport com.saveourtool.diktat.common.config.rules.RulesConfig\nimport com.saveourtool.diktat.ruleset.rules.chapter1.PackageNaming\nimport com.saveourtool.diktat.util.FixTestBase\n\nimport generated.WarningNames\nimport org.junit.jupiter.api.Tag\nimport org.junit.jupiter.api.Test\nimport org.junit.jupiter.api.io.TempDir\nimport java.nio.file.Path\n\nclass PackagePathFixTest : FixTestBase(\n    \"test/paragraph1/naming/package/src/main/kotlin\",\n    ::PackageNaming,\n    listOf(RulesConfig(\"DIKTAT_COMMON\", true, mapOf(\"domainName\" to \"com.saveourtool.diktat\")))\n) {\n    @Test\n    @Tag(WarningNames.PACKAGE_NAME_INCORRECT_PATH)\n    fun `fixing package name that differs from a path`() {\n        fixAndCompare(\"com/saveourtool/diktat/some/name/FixIncorrectExpected.kt\", \"com/saveourtool/diktat/some/name/FixIncorrectTest.kt\")\n    }\n\n    @Test\n    @Tag(WarningNames.PACKAGE_NAME_INCORRECT_PATH)\n    fun `fixing package name that differs from a path - regression one-word package name`() {\n        fixAndCompare(\"com/saveourtool/diktat/some/name/FixPackageRegressionExpected.kt\", \"com/saveourtool/diktat/some/name/FixPackageRegressionTest.kt\")\n    }\n\n    @Test\n    @Tag(WarningNames.PACKAGE_NAME_INCORRECT_PATH)\n    fun `fixing package name that differs from a path without domain`() {\n        fixAndCompare(\"some/FixIncorrectExpected.kt\", \"some/FixIncorrectTest.kt\")\n    }\n\n    @Test\n    @Tag(WarningNames.PACKAGE_NAME_MISSING)\n    fun `fix missing package name with file annotation`() {\n        fixAndCompare(\"com/saveourtool/diktat/some/name/FixMissingWithAnnotationExpected.kt\", \"com/saveourtool/diktat/some/name/FixMissingWithAnnotationTest.kt\")\n    }\n\n    @Test\n    @Tag(WarningNames.PACKAGE_NAME_MISSING)\n    fun `fix missing package name with file annotation and comments`() {\n        fixAndCompare(\"com/saveourtool/diktat/some/name/FixMissingWithAnnotationExpected2.kt\", \"com/saveourtool/diktat/some/name/FixMissingWithAnnotationTest2.kt\")\n    }\n\n    @Test\n    @Tag(WarningNames.PACKAGE_NAME_MISSING)\n    fun `fix missing package name with file annotation and comments 2`() {\n        fixAndCompare(\"com/saveourtool/diktat/some/name/FixMissingWithAnnotationExpected3.kt\", \"com/saveourtool/diktat/some/name/FixMissingWithAnnotationTest3.kt\")\n    }\n\n    // If there is no import list in code, the node is still present in the AST, but without any whitespaces around\n    // So, this check covered case, when we manually add whitespace before package directive\n    @Test\n    @Tag(WarningNames.PACKAGE_NAME_MISSING)\n    fun `fix missing package name without import list`() {\n        fixAndCompare(\"com/saveourtool/diktat/some/name/FixMissingWithoutImportExpected.kt\", \"com/saveourtool/diktat/some/name/FixMissingWithoutImportTest.kt\")\n    }\n\n    @Test\n    @Tag(WarningNames.PACKAGE_NAME_MISSING)\n    fun `fix missing package name with a proper location without domain`() {\n        fixAndCompare(\"some/FixMissingExpected.kt\", \"some/FixMissingTest.kt\")\n    }\n\n    @Test\n    @Tag(WarningNames.PACKAGE_NAME_MISSING)\n    fun `fix missing package name with a proper location`() {\n        fixAndCompare(\"com/saveourtool/diktat/some/name/FixMissingExpected.kt\", \"com/saveourtool/diktat/some/name/FixMissingTest.kt\")\n    }\n\n    @Test\n    @Tag(WarningNames.PACKAGE_NAME_MISSING)\n    fun `several empty lines after package`(@TempDir tempDir: Path) {\n        fixAndCompareContent(\n            expectedContent = \"\"\"\n                package com.saveourtool.diktat\n                /**\n                 * @param bar\n                 * @return something\n                 */\n                fun foo1(bar: Bar): Baz {\n                    // placeholder\n                }\n            \"\"\".trimIndent(),\n            actualContent = \"\"\"\n                /**\n                 * @param bar\n                 * @return something\n                 */\n                fun foo1(bar: Bar): Baz {\n                    // placeholder\n                }\n            \"\"\".trimIndent(),\n            subFolder = \"src/main/kotlin/com/saveourtool/diktat\",\n            tempDir = tempDir,\n        ).assertSuccessful()\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/test/kotlin/com/saveourtool/diktat/ruleset/chapter2/CommentsFormattingFixTest.kt",
    "content": "package com.saveourtool.diktat.ruleset.chapter2\n\nimport com.saveourtool.diktat.ruleset.chapter2.CommentsFormattingTest.Companion.indentStyleComment\nimport com.saveourtool.diktat.ruleset.rules.chapter2.kdoc.CommentsFormatting\nimport com.saveourtool.diktat.util.FixTestBase\n\nimport generated.WarningNames.COMMENT_WHITE_SPACE\nimport generated.WarningNames.FIRST_COMMENT_NO_BLANK_LINE\nimport generated.WarningNames.IF_ELSE_COMMENTS\nimport generated.WarningNames.WRONG_NEWLINES_AROUND_KDOC\nimport org.junit.jupiter.api.Tag\nimport org.junit.jupiter.api.Tags\nimport org.junit.jupiter.api.Test\nimport org.junit.jupiter.api.io.TempDir\n\nimport java.nio.file.Path\n\nclass CommentsFormattingFixTest : FixTestBase(\"test/paragraph2/kdoc/\", ::CommentsFormatting) {\n    @Test\n    @Tag(WRONG_NEWLINES_AROUND_KDOC)\n    fun `there should be no blank line between kdoc and it's declaration code`() {\n        fixAndCompare(\"KdocEmptyLineExpected.kt\", \"KdocEmptyLineTest.kt\")\n    }\n\n    @Test\n    @Tags(\n        Tag(WRONG_NEWLINES_AROUND_KDOC),\n        Tag(COMMENT_WHITE_SPACE),\n        Tag(IF_ELSE_COMMENTS),\n        Tag(FIRST_COMMENT_NO_BLANK_LINE)\n    )\n    fun `check lines and spaces in comments`() {\n        fixAndCompare(\"KdocCodeBlocksFormattingExpected.kt\", \"KdocCodeBlocksFormattingTest.kt\")\n    }\n\n    @Test\n    @Tags(Tag(WRONG_NEWLINES_AROUND_KDOC), Tag(FIRST_COMMENT_NO_BLANK_LINE))\n    fun `test example from code style`() {\n        fixAndCompare(\"KdocCodeBlockFormattingExampleExpected.kt\", \"KdocCodeBlockFormattingExampleTest.kt\")\n    }\n\n    @Test\n    @Tag(WRONG_NEWLINES_AROUND_KDOC)\n    fun `regression - should not insert newline before the first comment in a file`() {\n        fixAndCompare(\"NoPackageNoImportExpected.kt\", \"NoPackageNoImportTest.kt\")\n    }\n\n    /**\n     * `indent(1)` and `style(9)` style comments.\n     */\n    @Test\n    @Tag(COMMENT_WHITE_SPACE)\n    fun `indent-style header in a block comment should be preserved`(@TempDir tempDir: Path) {\n        val lintResult = fixAndCompareContent(indentStyleComment, tempDir = tempDir)\n        lintResult.assertSuccessful()\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/test/kotlin/com/saveourtool/diktat/ruleset/chapter2/CommentsFormattingTest.kt",
    "content": "package com.saveourtool.diktat.ruleset.chapter2\n\nimport com.saveourtool.diktat.common.config.rules.DIKTAT_RULE_SET_ID\nimport com.saveourtool.diktat.ruleset.constants.Warnings\nimport com.saveourtool.diktat.ruleset.constants.Warnings.IF_ELSE_COMMENTS\nimport com.saveourtool.diktat.ruleset.rules.chapter2.kdoc.CommentsFormatting\nimport com.saveourtool.diktat.util.LintTestBase\n\nimport com.saveourtool.diktat.api.DiktatError\nimport generated.WarningNames\nimport org.intellij.lang.annotations.Language\nimport org.junit.jupiter.api.Tag\nimport org.junit.jupiter.api.Test\n\nclass CommentsFormattingTest : LintTestBase(::CommentsFormatting) {\n    private val ruleId = \"$DIKTAT_RULE_SET_ID:${CommentsFormatting.NAME_ID}\"\n\n    @Test\n    @Tag(WarningNames.COMMENT_WHITE_SPACE)\n    fun `check white space before comment good`() {\n        val code =\n            \"\"\"\n                |package com.saveourtool.diktat.ruleset.chapter3\n                |\n                |class Example {\n                |    // First Comment\n                |    private val log = LoggerFactory.getLogger(Example.javaClass)\n                |}\n            \"\"\".trimMargin()\n\n        lintMethod(code)\n    }\n\n    @Test\n    @Tag(WarningNames.COMMENT_WHITE_SPACE)\n    fun `check white space before comment bad 2`() {\n        val code =\n            \"\"\"\n                |package com.saveourtool.diktat.ruleset.chapter3\n                |\n                |class Example {\n                |    val s = RulesConfig(WRONG_INDENTATION.name, true,\n                |            mapOf(\n                |                    \"newlineAtEnd\" to \"true\",     // comment\n                |                    \"extendedIndentOfParameters\" to \"true\",\n                |                    \"alignedParameters\" to \"true\",\n                |                    \"extendedIndentAfterOperators\" to \"true\"\n                |            )\n                |    )\n                |}\n            \"\"\".trimMargin()\n\n        lintMethod(code,\n            DiktatError(6, 51, ruleId, \"${Warnings.COMMENT_WHITE_SPACE.warnText()} There should be 2 space(s) before comment text, but there are too many in // comment\", true))\n    }\n\n    @Test\n    @Tag(WarningNames.COMMENT_WHITE_SPACE)\n    fun `check white space before comment bad 3`() {\n        val code =\n            \"\"\"\n                |package com.saveourtool.diktat.ruleset.chapter3\n                |\n                |@Suppress(\"RULE\")    // asdasd\n                |class Example {\n                |\n                |}\n            \"\"\".trimMargin()\n\n        lintMethod(code,\n            DiktatError(3, 22, ruleId, \"${Warnings.COMMENT_WHITE_SPACE.warnText()} There should be 2 space(s) before comment text, but there are too many in // asdasd\", true))\n    }\n\n    @Test\n    @Tag(WarningNames.COMMENT_WHITE_SPACE)\n    fun `check white space before comment good2`() {\n        val code =\n            \"\"\"\n                |package com.saveourtool.diktat.ruleset.chapter3\n                |\n                |/* This is a comment */\n                |class Example {\n                |    /**\n                |    *\n                |    * Some Comment\n                |    */\n                |    private val log = LoggerFactory.getLogger(Example.javaClass)\n                |\n                |    fun a() {\n                |       // When comment\n                |       when(1) {\n                |           1 -> print(1)\n                |       }\n                |    }\n                |    /*\n                |       Some Comment\n                |    */\n                |}\n            \"\"\".trimMargin()\n\n        lintMethod(code)\n    }\n\n    @Test\n    @Tag(WarningNames.COMMENT_WHITE_SPACE)\n    fun `check comment before package good`() {\n        val code =\n            \"\"\"\n                |// This is a comment before package\n                |package com.saveourtool.diktat.ruleset.chapter3\n                |\n                |// This is a comment\n                |class Example {\n                |\n                |}\n            \"\"\".trimMargin()\n\n        lintMethod(code)\n    }\n\n    @Test\n    @Tag(WarningNames.COMMENT_WHITE_SPACE)\n    fun `check white space before comment bad`() {\n        val code =\n            \"\"\"\n                |package com.saveourtool.diktat.ruleset.chapter3\n                |\n                |class Example {\n                |    //First Comment\n                |    private val log = LoggerFactory.getLogger(Example.javaClass)\n                |\n                |    /**\n                |    *      Some comment\n                |    */\n                |\n                |    /*     Comment */\n                |}\n            \"\"\".trimMargin()\n\n        lintMethod(code,\n            DiktatError(4, 5, ruleId, \"${Warnings.COMMENT_WHITE_SPACE.warnText()} There should be 1 space(s) before comment token in //First Comment\", true),\n            DiktatError(11, 5, ruleId, \"${Warnings.COMMENT_WHITE_SPACE.warnText()} There should be 1 space(s) before comment token in /*     Comment */\", true))\n    }\n\n    @Test\n    @Tag(WarningNames.WRONG_NEWLINES_AROUND_KDOC)\n    fun `check new line above comment good`() {\n        val code =\n            \"\"\"\n                |package com.saveourtool.diktat.ruleset.chapter3\n                |\n                |class Example {\n                |    private val log = LoggerFactory.getLogger(Example.javaClass)\n                |\n                |    // Another Comment\n                |    private val some = 5\n                |\n                |    fun someFunc() {\n                |       /* First comment */\n                |       val first = 5  // Some comment\n                |\n                |       /**\n                |       * kDoc comment\n                |       * some text\n                |       */\n                |       val second = 6\n                |\n                |       /**\n                |       * asdasd\n                |       */\n                |       fun testFunc() {\n                |           val a = 5  // Some Comment\n                |\n                |           // Fun in fun Block\n                |           val b = 6\n                |       }\n                |    }\n                |}\n            \"\"\".trimMargin()\n\n        lintMethod(code)\n    }\n\n    @Test\n    @Tag(WarningNames.WRONG_NEWLINES_AROUND_KDOC)\n    fun `check file new line above comment good`() {\n        val code =\n            \"\"\"\n                |package com.saveourtool.diktat.ruleset.chapter3\n                |\n                |// Some comment\n                |class Example {\n                |\n                |}\n                |\n                |// Some comment 2\n                |class AnotherExample {\n                |\n                |}\n            \"\"\".trimMargin()\n\n        lintMethod(code)\n    }\n\n    @Test\n    @Tag(WarningNames.WRONG_NEWLINES_AROUND_KDOC)\n    fun `check file new line above comment bad`() {\n        val code =\n            \"\"\"\n                |package com.saveourtool.diktat.ruleset.chapter3\n                |// Some comment\n                |class Example {\n                |\n                |}\n                |\n                |// Some comment 2\n                |class AnotherExample {\n                |\n                |}\n            \"\"\".trimMargin()\n\n        lintMethod(code,\n            DiktatError(2, 1, ruleId, \"${Warnings.WRONG_NEWLINES_AROUND_KDOC.warnText()} // Some comment\", true))\n    }\n\n    @Test\n    @Tag(WarningNames.WRONG_NEWLINES_AROUND_KDOC)\n    fun `check file new line above comment bad - block and kDOC comments`() {\n        val code =\n            \"\"\"\n                |package com.saveourtool.diktat.ruleset.chapter3\n                |/* Some comment */\n                |class Example {\n                |\n                |}\n                |/**\n                |* Some comment 2\n                |*/\n                |\n                |class AnotherExample {\n                |\n                |}\n            \"\"\".trimMargin()\n\n        lintMethod(code,\n            DiktatError(2, 1, ruleId, \"${Warnings.WRONG_NEWLINES_AROUND_KDOC.warnText()} /* Some comment */\", true),\n            DiktatError(6, 1, ruleId, \"${Warnings.WRONG_NEWLINES_AROUND_KDOC.warnText()} /**...\", true),\n            DiktatError(8, 3, ruleId, \"${Warnings.WRONG_NEWLINES_AROUND_KDOC.warnText()} redundant blank line after /**...\", true))\n    }\n\n    @Test\n    @Tag(WarningNames.COMMENT_WHITE_SPACE)\n    fun `check right side comments - good`() {\n        val code =\n            \"\"\"\n                |package com.saveourtool.diktat.ruleset.chapter3\n                |\n                |/* Some comment */\n                |class Example {\n                |   val a = 5  // This is a comment\n                |}\n            \"\"\".trimMargin()\n\n        lintMethod(code)\n    }\n\n    @Test\n    @Tag(WarningNames.COMMENT_WHITE_SPACE)\n    fun `check right side comments - bad`() {\n        val code =\n            \"\"\"\n                |package com.saveourtool.diktat.ruleset.chapter3\n                |\n                |/* Some comment */\n                |class Example {\n                |   val a = 5// This is a comment\n                |}\n            \"\"\".trimMargin()\n\n        lintMethod(code,\n            DiktatError(5, 13, ruleId, \"${Warnings.COMMENT_WHITE_SPACE.warnText()} There should be 2 space(s) before comment text, but are none in // This is a comment\", true))\n    }\n\n    @Test\n    @Tag(WarningNames.IF_ELSE_COMMENTS)\n    fun `if - else comments good`() {\n        val code =\n            \"\"\"\n                |package com.saveourtool.diktat.ruleset.chapter3\n                |\n                |class Example {\n                |   fun someFunc() {\n                |       // general if comment\n                |       if(a = 5) {\n                |\n                |       }\n                |       else {\n                |           // Good Comment\n                |           print(5)\n                |       }\n                |   }\n                |}\n            \"\"\".trimMargin()\n\n        lintMethod(code)\n    }\n\n    @Test\n    @Tag(WarningNames.IF_ELSE_COMMENTS)\n    fun `if - else comments good 2`() {\n        val code =\n            \"\"\"\n                |package com.saveourtool.diktat.ruleset.chapter3\n                |\n                |class Example {\n                |   fun someFunc() {\n                |       // general if comment\n                |       if(a = 5) {\n                |\n                |       } else\n                |           // Good Comment\n                |           print(5)\n                |   }\n                |}\n            \"\"\".trimMargin()\n\n        lintMethod(code)\n    }\n\n    @Test\n    @Tag(WarningNames.IF_ELSE_COMMENTS)\n    fun `if - else comments bad`() {\n        val code =\n            \"\"\"\n                |package com.saveourtool.diktat.ruleset.chapter3\n                |\n                |class Example {\n                |   fun someFunc() {\n                |       // general if comment\n                |       if(a = 5) {\n                |\n                |       }\n                |       // Bad Comment\n                |       else {\n                |           print(5)\n                |       }\n                |   }\n                |}\n            \"\"\".trimMargin()\n\n        lintMethod(code,\n            DiktatError(6, 8, ruleId, \"${IF_ELSE_COMMENTS.warnText()} // Bad Comment\", true))\n    }\n\n    @Test\n    @Tag(WarningNames.IF_ELSE_COMMENTS)\n    fun `if - else comments bad 3`() {\n        val code =\n            \"\"\"\n                |package com.saveourtool.diktat.ruleset.chapter3\n                |\n                |class Example {\n                |   fun someFunc() {\n                |       // general if comment\n                |       if(a = 5) {\n                |\n                |       }  /* Some comment */ else {\n                |           print(5)\n                |       }\n                |   }\n                |}\n            \"\"\".trimMargin()\n\n        lintMethod(code,\n            DiktatError(6, 8, ruleId, \"${IF_ELSE_COMMENTS.warnText()} /* Some comment */\", true))\n    }\n\n    @Test\n    @Tag(WarningNames.IF_ELSE_COMMENTS)\n    fun `if - else comments bad 4`() {\n        val code =\n            \"\"\"\n                |package com.saveourtool.diktat.ruleset.chapter3\n                |\n                |class Example {\n                |   fun someFunc() {\n                |       // general if comment\n                |       if(a = 5) {\n                |\n                |       }  /* Some comment */ else\n                |           print(5)\n                |   }\n                |}\n            \"\"\".trimMargin()\n\n        lintMethod(code,\n            DiktatError(6, 8, ruleId, \"${IF_ELSE_COMMENTS.warnText()} /* Some comment */\", true))\n    }\n\n    @Test\n    @Tag(WarningNames.IF_ELSE_COMMENTS)\n    fun `should not trigger on comment`() {\n        val code =\n            \"\"\"\n                |package com.saveourtool.diktat.ruleset.chapter3\n                |\n                |class Example {\n                |   fun someFunc() {\n                |       // general if comment\n                |       if(a = 5) {\n                |           /* Some comment */\n                |       } else {\n                |           print(5)\n                |       }\n                |   }\n                |}\n            \"\"\".trimMargin()\n\n        lintMethod(code)\n    }\n\n    @Test\n    @Tag(WarningNames.FIRST_COMMENT_NO_BLANK_LINE)\n    fun `first comment no space in if - else bad`() {\n        val code =\n            \"\"\"\n                |package com.saveourtool.diktat.ruleset.chapter3\n                |\n                |class Example {\n                |   fun someFunc() {\n                |       // general if comment\n                |       if(a = 5) {\n                |\n                |       } else {  // Bad Comment\n                |           print(5)\n                |       }\n                |   }\n                |}\n            \"\"\".trimMargin()\n\n        lintMethod(code,\n            DiktatError(8, 18, ruleId, \"${Warnings.FIRST_COMMENT_NO_BLANK_LINE.warnText()} // Bad Comment\", true))\n    }\n\n    @Test\n    @Tag(WarningNames.COMMENT_WHITE_SPACE)\n    fun `check comment in class bad`() {\n        val code =\n            \"\"\"\n                |package com.saveourtool.diktat.ruleset.chapter3\n                |\n                |class Example {\n                |    // First Comment\n                |    private val log = LoggerFactory.getLogger(Example.javaClass)  // secondComment\n                |}\n            \"\"\".trimMargin()\n\n        lintMethod(code)\n    }\n\n    @Test\n    @Tag(WarningNames.COMMENT_WHITE_SPACE)\n    fun `check comment on file level`() {\n        val code =\n            \"\"\"\n                | /*\n                |  * heh\n                |  */\n                |package com.saveourtool.diktat.ruleset.chapter3\n                |\n                |class Example {\n                |}\n            \"\"\".trimMargin()\n\n        lintMethod(code,\n            DiktatError(1, 2, ruleId, \"${Warnings.COMMENT_WHITE_SPACE.warnText()} There should be 0 space(s) before comment text, but are 1 in /*...\", true))\n    }\n\n    @Test\n    @Tag(WarningNames.COMMENT_WHITE_SPACE)\n    fun `check comment on file level without space`() {\n        val code =\n            \"\"\"\n                |/*\n                |  * heh\n                |  */\n                |package com.saveourtool.diktat.ruleset.chapter3\n                |\n                |class Example {\n                |}\n            \"\"\".trimMargin()\n\n        lintMethod(code)\n    }\n\n    /**\n     * `indent(1)` and `style(9)` style comments.\n     */\n    @Test\n    @Tag(WarningNames.COMMENT_WHITE_SPACE)\n    fun `indent-style header in a block comment should produce no warnings`() =\n        lintMethod(indentStyleComment)\n\n    internal companion object {\n        @Language(\"kotlin\")\n        internal val indentStyleComment = \"\"\"\n        |/*-\n        | * This is an indent-style comment, and it's different from regular\n        | * block comments in C-like languages.\n        | *\n        | * Code formatters should not wrap or reflow its content, so you can\n        | * safely insert code fragments:\n        | *\n        | * ```\n        | * int i = 42;\n        | * ```\n        | *\n        | * or ASCII diagrams:\n        | *\n        | * +-----+\n        | * | Box |\n        | * +-----+\n        | */\n        \"\"\".trimMargin()\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/test/kotlin/com/saveourtool/diktat/ruleset/chapter2/HeaderCommentRuleFixTest.kt",
    "content": "package com.saveourtool.diktat.ruleset.chapter2\n\nimport com.saveourtool.diktat.common.config.rules.RulesConfig\nimport com.saveourtool.diktat.ruleset.constants.Warnings.HEADER_MISSING_OR_WRONG_COPYRIGHT\nimport com.saveourtool.diktat.ruleset.constants.Warnings.HEADER_WRONG_FORMAT\nimport com.saveourtool.diktat.ruleset.rules.chapter2.comments.HeaderCommentRule\nimport com.saveourtool.diktat.test.framework.processing.ResourceReader.Companion.withReplacements\nimport com.saveourtool.diktat.util.FixTestBase\n\nimport generated.WarningNames\nimport generated.WarningNames.WRONG_COPYRIGHT_YEAR\nimport org.junit.jupiter.api.Tag\nimport org.junit.jupiter.api.Tags\nimport org.junit.jupiter.api.Test\nimport org.junit.jupiter.api.io.TempDir\nimport java.nio.file.Path\nimport java.time.LocalDate\n\nclass HeaderCommentRuleFixTest : FixTestBase(\n    \"test/paragraph2/header\",\n    ::HeaderCommentRule,\n    listOf(\n        RulesConfig(\"HEADER_MISSING_OR_WRONG_COPYRIGHT\", true,\n            mapOf(\n                \"isCopyrightMandatory\" to \"true\",\n                \"copyrightText\" to \"Copyright (c) Huawei Technologies Co., Ltd. 2020-$currentYear. All rights reserved.\")\n        ),\n        RulesConfig(\"HEADER_WRONG_FORMAT\", true, emptyMap())\n    )\n) {\n    @Test\n    @Tag(WarningNames.HEADER_WRONG_FORMAT)\n    fun `new line should be inserted after header KDoc`(@TempDir tempDir: Path) {\n        fixAndCompare(\"NewlineAfterHeaderKdocExpected.kt\", \"NewlineAfterHeaderKdocTest.kt\", overrideResourceReader = { it.withReplacements(tempDir, currentYearReplacement) })\n    }\n\n    @Test\n    @Tag(WarningNames.HEADER_MISSING_OR_WRONG_COPYRIGHT)\n    fun `if no copyright is present and mandatoryCopyright=true, it is added`(@TempDir tempDir: Path) {\n        fixAndCompare(\"AutoCopyrightExpected.kt\", \"AutoCopyrightTest.kt\", overrideResourceReader = { it.withReplacements(tempDir, currentYearReplacement) })\n    }\n\n    @Test\n    @Tag(WarningNames.HEADER_MISSING_OR_WRONG_COPYRIGHT)\n    fun `if no copyright is present, added it and apply pattern for current year`(@TempDir tempDir: Path) {\n        fixAndCompare(\"AutoCopyrightApplyPatternExpected.kt\", \"AutoCopyrightApplyPatternTest.kt\",\n            listOf(\n                RulesConfig(\n                    HEADER_MISSING_OR_WRONG_COPYRIGHT.name, true,\n                    mapOf(\n                        \"isCopyrightMandatory\" to \"true\",\n                        \"copyrightText\" to \"Copyright (c) Huawei Technologies Co., Ltd. 2020-;@currYear;. All rights reserved.\"\n                    )\n                ),\n                RulesConfig(HEADER_WRONG_FORMAT.name, true, emptyMap())\n            ),\n            overrideResourceReader = { it.withReplacements(tempDir, currentYearReplacement) },\n        )\n    }\n\n    /**\n     * Fixme there shouldn't be an additional blank line after copyright\n     */\n    @Test\n    @Tag(WarningNames.HEADER_NOT_BEFORE_PACKAGE)\n    fun `header KDoc should be moved before package`(@TempDir tempDir: Path) {\n        fixAndCompare(\"MisplacedHeaderKdocExpected.kt\", \"MisplacedHeaderKdocTest.kt\", overrideResourceReader = { it.withReplacements(tempDir, currentYearReplacement) })\n    }\n\n    @Test\n    @Tags(Tag(WarningNames.HEADER_MISSING_OR_WRONG_COPYRIGHT), Tag(WarningNames.HEADER_WRONG_FORMAT))\n    fun `header KDoc should be moved before package - no copyright`(@TempDir tempDir: Path) {\n        fixAndCompare(\"MisplacedHeaderKdocNoCopyrightExpected.kt\", \"MisplacedHeaderKdocNoCopyrightTest.kt\",\n            listOf(RulesConfig(HEADER_MISSING_OR_WRONG_COPYRIGHT.name, false, emptyMap()), RulesConfig(HEADER_WRONG_FORMAT.name, true, emptyMap())),\n            overrideResourceReader = { it.withReplacements(tempDir, currentYearReplacement) },\n        )\n    }\n\n    @Test\n    @Tags(Tag(WarningNames.HEADER_NOT_BEFORE_PACKAGE), Tag(WarningNames.HEADER_MISSING_OR_WRONG_COPYRIGHT))\n    fun `header KDoc should be moved before package - appended copyright`(@TempDir tempDir: Path) {\n        fixAndCompare(\n            \"MisplacedHeaderKdocAppendedCopyrightExpected.kt\",\n            \"MisplacedHeaderKdocAppendedCopyrightTest.kt\",\n            overrideResourceReader = { it.withReplacements(tempDir, currentYearReplacement) },\n        )\n    }\n\n    @Test\n    @Tag(WRONG_COPYRIGHT_YEAR)\n    fun `copyright invalid year should be auto-corrected`(@TempDir tempDir: Path) {\n        fixAndCompare(\"CopyrightDifferentYearExpected.kt\", \"CopyrightDifferentYearTest.kt\",\n            listOf(RulesConfig(HEADER_MISSING_OR_WRONG_COPYRIGHT.name, true, mapOf(\n                \"isCopyrightMandatory\" to \"true\",\n                \"copyrightText\" to \"Copyright (c) My Company., Ltd. 2012-2019. All rights reserved.\"\n            ))),\n            overrideResourceReader = { it.withReplacements(tempDir, currentYearReplacement) },\n        )\n    }\n\n    @Test\n    @Tag(WRONG_COPYRIGHT_YEAR)\n    fun `copyright invalid year should be auto-corrected 2`(@TempDir tempDir: Path) {\n        fixAndCompare(\"CopyrightDifferentYearExpected2.kt\", \"CopyrightDifferentYearTest2.kt\",\n            listOf(RulesConfig(HEADER_MISSING_OR_WRONG_COPYRIGHT.name, true, mapOf(\n                \"isCopyrightMandatory\" to \"true\",\n                \"copyrightText\" to \"Copyright (c) My Company., Ltd. 2021. All rights reserved.\"\n            ))),\n            overrideResourceReader = { it.withReplacements(tempDir, currentYearReplacement) },\n        )\n    }\n\n    @Test\n    @Tag(WRONG_COPYRIGHT_YEAR)\n    fun `copyright invalid pattern, but valid in code`(@TempDir tempDir: Path) {\n        fixAndCompare(\"CopyrightInvalidPatternValidCodeExpected.kt\", \"CopyrightInvalidPatternValidCodeTest.kt\",\n            listOf(RulesConfig(HEADER_MISSING_OR_WRONG_COPYRIGHT.name, true, mapOf(\n                \"isCopyrightMandatory\" to \"true\",\n                \"copyrightText\" to \"Copyright (c) My Company., Ltd. 2012-2019. All rights reserved.\"\n            ))),\n            overrideResourceReader = { it.withReplacements(tempDir, currentYearReplacement) },\n        )\n    }\n\n    @Test\n    @Tag(WRONG_COPYRIGHT_YEAR)\n    fun `copyright invalid pattern, update actual year in it and auto-correct`(@TempDir tempDir: Path) {\n        fixAndCompare(\"CopyrightAbsentInvalidPatternExpected.kt\", \"CopyrightAbsentInvalidPatternTest.kt\",\n            listOf(RulesConfig(HEADER_MISSING_OR_WRONG_COPYRIGHT.name, true, mapOf(\n                \"isCopyrightMandatory\" to \"true\",\n                \"copyrightText\" to \"Copyright (c) My Company., Ltd. 2012-2019. All rights reserved.\"\n            ))),\n            overrideResourceReader = { it.withReplacements(tempDir, currentYearReplacement) },\n        )\n    }\n\n    @Test\n    @Tag(WRONG_COPYRIGHT_YEAR)\n    fun `should not raise npe`(@TempDir tempDir: Path) {\n        fixAndCompare(\"CopyrightShouldNotTriggerNPEExpected.kt\", \"CopyrightShouldNotTriggerNPETest.kt\",\n            listOf(RulesConfig(HEADER_MISSING_OR_WRONG_COPYRIGHT.name, true, mapOf(\n                \"isCopyrightMandatory\" to \"true\",\n                \"copyrightText\" to \"Copyright (c) My Company., Ltd. 2012-2021. All rights reserved.\"\n            ))),\n            overrideResourceReader = { it.withReplacements(tempDir, currentYearReplacement) },\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.HEADER_MISSING_OR_WRONG_COPYRIGHT)\n    fun `copyright multiline`(@TempDir tempDir: Path) {\n        fixAndCompare(\"MultilineCopyrightExample.kt\", \"MultilineCopyrightTest.kt\",\n            listOf(RulesConfig(HEADER_MISSING_OR_WRONG_COPYRIGHT.name, true, mapOf(\n                \"isCopyrightMandatory\" to \"true\",\n                \"copyrightText\" to \"\"\"\n                |    Copyright 2018-$currentYear John Doe.\n                |\n                |    Licensed under the Apache License, Version 2.0 (the \"License\");\n                |    you may not use this file except in compliance with the License.\n                |    You may obtain a copy of the License at\n                |\n                |        http://www.apache.org/licenses/LICENSE-2.0\n                |\n                |    Unless required by applicable law or agreed to in writing, software\n                |    distributed under the License is distributed on an \"AS IS\" BASIS,\n                |    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n                |    See the License for the specific language governing permissions and\n                |    limitations under the License.\n                \"\"\".trimMargin()\n            ))),\n            overrideResourceReader = { it.withReplacements(tempDir, currentYearReplacement) },\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.HEADER_MISSING_OR_WRONG_COPYRIGHT)\n    fun `should not trigger if copyright text have different indents`(@TempDir tempDir: Path) {\n        fixAndCompare(\"MultilineCopyrightNotTriggerExample.kt\", \"MultilineCopyrightNotTriggerTest.kt\",\n            listOf(RulesConfig(HEADER_MISSING_OR_WRONG_COPYRIGHT.name, true, mapOf(\n                \"isCopyrightMandatory\" to \"true\",\n                \"copyrightText\" to \"\"\"\n                    |   Copyright 2018-2020 John Doe.\n                    |\n                    |   Licensed under the Apache License, Version 2.0 (the \"License\");\n                    |   you may not use this file except in compliance with the License.\n                    |   You may obtain a copy of the License at\n            \"\"\".trimMargin()\n            ))),\n            overrideResourceReader = { it.withReplacements(tempDir, currentYearReplacement) },\n        )\n    }\n\n    companion object {\n        private const val PLACEHOLDER = \"%%YEAR%%\"\n        private val currentYear = LocalDate.now().year.toString()\n        private val currentYearReplacement = mapOf(PLACEHOLDER to currentYear)\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/test/kotlin/com/saveourtool/diktat/ruleset/chapter2/HeaderCommentRuleTest.kt",
    "content": "package com.saveourtool.diktat.ruleset.chapter2\n\nimport com.saveourtool.diktat.common.config.rules.DIKTAT_RULE_SET_ID\nimport com.saveourtool.diktat.common.config.rules.RulesConfig\nimport com.saveourtool.diktat.ruleset.constants.Warnings\nimport com.saveourtool.diktat.ruleset.constants.Warnings.HEADER_MISSING_IN_NON_SINGLE_CLASS_FILE\nimport com.saveourtool.diktat.ruleset.constants.Warnings.HEADER_MISSING_OR_WRONG_COPYRIGHT\nimport com.saveourtool.diktat.ruleset.constants.Warnings.HEADER_NOT_BEFORE_PACKAGE\nimport com.saveourtool.diktat.ruleset.constants.Warnings.HEADER_WRONG_FORMAT\nimport com.saveourtool.diktat.ruleset.rules.chapter2.comments.HeaderCommentRule\nimport com.saveourtool.diktat.util.LintTestBase\n\nimport com.saveourtool.diktat.api.DiktatError\nimport generated.WarningNames\nimport org.junit.jupiter.api.Tag\nimport org.junit.jupiter.api.Test\nimport org.junit.jupiter.api.io.TempDir\nimport java.nio.file.Path\n\nimport java.time.LocalDate\n\nclass HeaderCommentRuleTest : LintTestBase(::HeaderCommentRule) {\n    private val ruleId: String = \"$DIKTAT_RULE_SET_ID:${HeaderCommentRule.NAME_ID}\"\n    private val curYear = LocalDate.now().year\n    private val rulesConfigList: List<RulesConfig> = listOf(\n        RulesConfig(\"HEADER_MISSING_OR_WRONG_COPYRIGHT\", true,\n            mapOf(\"copyrightText\" to \"Copyright (c) My Company, Ltd. 2012-$curYear. All rights reserved.\"))\n    )\n    private val rulesConfigListWithPattern: List<RulesConfig> = listOf(\n        RulesConfig(\"HEADER_MISSING_OR_WRONG_COPYRIGHT\", true,\n            mapOf(\"copyrightText\" to \"Copyright (c) My Company, Ltd. 2012-;@currYear;. All rights reserved.\"))\n    )\n    private val rulesConfigListInvalidYear: List<RulesConfig> = listOf(\n        RulesConfig(\"HEADER_MISSING_OR_WRONG_COPYRIGHT\", true,\n            mapOf(\"copyrightText\" to \"Copyright (c) My Company, Ltd. 2012-2019. All rights reserved.\"))\n    )\n    private val rulesConfigListInvalidYearBeforeCopyright: List<RulesConfig> = listOf(\n        RulesConfig(\"HEADER_MISSING_OR_WRONG_COPYRIGHT\", true,\n            mapOf(\"copyrightText\" to \"Copyright (c) 2019 My Company, Ltd. All rights reserved.\"))\n    )\n    private val rulesConfigListYear: List<RulesConfig> = listOf(\n        RulesConfig(\"HEADER_MISSING_OR_WRONG_COPYRIGHT\", true,\n            mapOf(\"copyrightText\" to \"Copyright (c) $curYear My Company, Ltd. All rights reserved.\"))\n    )\n    private val rulesConfigListYearWithPattern: List<RulesConfig> = listOf(\n        RulesConfig(\"HEADER_MISSING_OR_WRONG_COPYRIGHT\", true,\n            mapOf(\"copyrightText\" to \"Copyright (c) ;@currYear; My Company, Ltd. All rights reserved.\"))\n    )\n    private val rulesConfigListCn: List<RulesConfig> = listOf(\n        RulesConfig(\"HEADER_MISSING_OR_WRONG_COPYRIGHT\", true,\n            mapOf(\"copyrightText\" to \"版权所有 (c) 华为技术有限公司 2012-$curYear\"))\n    )\n    private val curYearCopyright = \"Copyright (c) My Company, Ltd. 2012-$curYear. All rights reserved.\"\n    private val copyrightBlock = \"\"\"\n        /*\n         * $curYearCopyright\n         */\n    \"\"\".trimIndent()\n\n    @Test\n    @Tag(WarningNames.HEADER_WRONG_FORMAT)\n    fun `file header comment (positive example)`() {\n        lintMethod(\n            \"\"\"\n                $copyrightBlock\n                /**\n                 * Very useful description, why this file has two classes\n                 * foo bar baz\n                 */\n\n                package com.saveourtool.diktat.example\n\n                class Example1 { }\n\n                class Example2 { }\n            \"\"\".trimIndent(),\n            rulesConfigList = rulesConfigList\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.HEADER_WRONG_FORMAT)\n    fun `file header comment with Chinese version copyright (positive example)`() {\n        lintMethod(\n            \"\"\"\n                /*\n                 * 版权所有 (c) 华为技术有限公司 2012-$curYear\n                 */\n                /**\n                 * Very useful description, why this file has two classes\n                 * foo bar baz\n                 */\n\n                package com.saveourtool.diktat.example\n\n                class Example1 { }\n\n                class Example2 { }\n            \"\"\".trimIndent(),\n            rulesConfigList = rulesConfigListCn\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.HEADER_MISSING_OR_WRONG_COPYRIGHT)\n    fun `copyright should not be placed inside KDoc`() {\n        lintMethod(\n            \"\"\"\n                /**\n                 * $curYearCopyright\n                 */\n                /**\n                 * Very useful description, why this file has two classes\n                 * foo bar baz\n                 */\n\n                package com.saveourtool.diktat.example\n\n                class Example1 { }\n\n                class Example2 { }\n            \"\"\".trimIndent(),\n            DiktatError(1, 1, ruleId, \"${HEADER_MISSING_OR_WRONG_COPYRIGHT.warnText()} copyright is placed inside KDoc, but should be inside a block comment\", true),\n            rulesConfigList = rulesConfigList\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.HEADER_MISSING_OR_WRONG_COPYRIGHT)\n    fun `copyright should not be placed inside KDoc (Chinese version)`() {\n        lintMethod(\n            \"\"\"\n                /**\n                 * 版权所有 (c) 华为技术有限公司 2012-2020\n                 */\n                /**\n                 * Very useful description, why this file has two classes\n                 * foo bar baz\n                 */\n\n                package com.saveourtool.diktat.example\n\n                class Example1 { }\n\n                class Example2 { }\n            \"\"\".trimIndent(),\n            DiktatError(1, 1, ruleId, \"${HEADER_MISSING_OR_WRONG_COPYRIGHT.warnText()} copyright is placed inside KDoc, but should be inside a block comment\", true),\n            rulesConfigList = rulesConfigListCn\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.HEADER_MISSING_OR_WRONG_COPYRIGHT)\n    fun `copyright should not be placed inside single line comment`() {\n        lintMethod(\n            \"\"\"\n                // $curYearCopyright\n                /**\n                 * Very useful description, why this file has two classes\n                 * foo bar baz\n                 */\n\n                package com.saveourtool.diktat.example\n\n                class Example1 { }\n\n                class Example2 { }\n            \"\"\".trimIndent(),\n            DiktatError(1, 1, ruleId, \"${HEADER_MISSING_OR_WRONG_COPYRIGHT.warnText()} copyright is placed inside KDoc, but should be inside a block comment\", true),\n            rulesConfigList = rulesConfigList\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.WRONG_COPYRIGHT_YEAR)\n    fun `copyright year good`() {\n        lintMethod(\n            \"\"\"\n                /*\n                 * $curYearCopyright\n                 */\n                /**\n                 * Very useful description, why this file has two classes\n                 * foo bar baz\n                 */\n\n                package com.saveourtool.diktat.example\n\n                class Example1 { }\n\n                class Example2 { }\n            \"\"\".trimIndent(),\n            rulesConfigList = rulesConfigList\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.WRONG_COPYRIGHT_YEAR)\n    fun `copyright year good 2`() {\n        lintMethod(\n            \"\"\"\n                /*\n                 * Copyright (c) $curYear My Company, Ltd. All rights reserved.\n                 */\n                /**\n                 * Very useful description, why this file has two classes\n                 * foo bar baz\n                 */\n\n                package com.saveourtool.diktat.example\n\n                class Example1 { }\n\n                class Example2 { }\n            \"\"\".trimIndent(),\n            rulesConfigList = rulesConfigListYear\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.WRONG_COPYRIGHT_YEAR)\n    fun `copyright year good 3 - apply pattern`() {\n        lintMethod(\n            \"\"\"\n                /*\n                 * Copyright (c) $curYear My Company, Ltd. All rights reserved.\n                 */\n                /**\n                 * Very useful description, why this file has two classes\n                 * foo bar baz\n                 */\n\n                package com.saveourtool.diktat.example\n\n                class Example1 { }\n\n                class Example2 { }\n            \"\"\".trimIndent(),\n            rulesConfigList = rulesConfigListYearWithPattern\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.WRONG_COPYRIGHT_YEAR)\n    fun `copyright year good 4 - apply pattern`() {\n        lintMethod(\n            \"\"\"\n                /*\n                 * Copyright (c) My Company, Ltd. 2012-$curYear. All rights reserved.\n                 */\n                /**\n                 * Very useful description, why this file has two classes\n                 * foo bar baz\n                 */\n\n                package com.saveourtool.diktat.example\n\n                class Example1 { }\n\n                class Example2 { }\n            \"\"\".trimIndent(),\n            rulesConfigList = rulesConfigListWithPattern\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.WRONG_COPYRIGHT_YEAR)\n    fun `copyright year good 5`() {\n        lintMethod(\n            \"\"\"\n                /*\n                   Copyright (c) My Company, Ltd. 2021-$curYear. All rights reserved.\n                 */\n                /**\n                 * Very useful description, why this file has two classes\n                 * foo bar baz\n                 */\n\n                package com.saveourtool.diktat.example\n\n                class Example1 { }\n\n                class Example2 { }\n            \"\"\".trimIndent(),\n            rulesConfigList = rulesConfigList\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.WRONG_COPYRIGHT_YEAR)\n    fun `copyright year good 6`() {\n        lintMethod(\n            \"\"\"\n                /*\n                 *  Copyright (c) My Company, Ltd. 2002-$curYear. All rights reserved.\n                 */\n                /**\n                 * Very useful description, why this file has two classes\n                 * foo bar baz\n                 */\n\n                package com.saveourtool.diktat.example\n\n                class Example1 { }\n\n                class Example2 { }\n            \"\"\".trimIndent(),\n            rulesConfigList = rulesConfigList\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.WRONG_COPYRIGHT_YEAR)\n    fun `copyright year bad`() {\n        lintMethod(\n            \"\"\"\n                /*\n                 * Copyright (c) My Company, Ltd. 2012-2019. All rights reserved.\n                 */\n                /**\n                 * Very useful description, why this file has two classes\n                 * foo bar baz\n                 */\n\n                package com.saveourtool.diktat.example\n\n                class Example1 { }\n\n                class Example2 { }\n            \"\"\".trimIndent(),\n            DiktatError(1, 1, ruleId, \"\"\"${Warnings.WRONG_COPYRIGHT_YEAR.warnText()} year should be ${LocalDate.now().year}\"\"\", true),\n            rulesConfigList = rulesConfigListInvalidYear\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.WRONG_COPYRIGHT_YEAR)\n    fun `copyright year bad 2`() {\n        lintMethod(\n            \"\"\"\n                /*\n                 * Copyright (c) 2019 My Company, Ltd. All rights reserved.\n                 */\n                /**\n                 * Very useful description, why this file has two classes\n                 * foo bar baz\n                 */\n\n                package com.saveourtool.diktat.example\n\n                class Example1 { }\n\n                class Example2 { }\n            \"\"\".trimIndent(),\n            DiktatError(1, 1, ruleId, \"\"\"${Warnings.WRONG_COPYRIGHT_YEAR.warnText()} year should be ${LocalDate.now().year}\"\"\", true),\n            rulesConfigList = rulesConfigListInvalidYearBeforeCopyright\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.HEADER_MISSING_IN_NON_SINGLE_CLASS_FILE)\n    fun `file with zero classes should have header KDoc`() {\n        lintMethod(\n            \"\"\"\n                package com.saveourtool.diktat.example\n\n                val CONSTANT = 42\n\n                fun foo(): Int = 42\n            \"\"\".trimIndent(),\n            DiktatError(1, 1, ruleId, \"${HEADER_MISSING_IN_NON_SINGLE_CLASS_FILE.warnText()} there are 0 declared classes and/or objects\", false),\n            rulesConfigList = rulesConfigList\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.HEADER_MISSING_IN_NON_SINGLE_CLASS_FILE)\n    fun `file with multiple classes should have header KDoc`() {\n        lintMethod(\n            \"\"\"\n                package com.saveourtool.diktat.example\n\n                class Example1 { }\n\n                class Example2 { }\n            \"\"\".trimIndent(),\n            DiktatError(1, 1, ruleId, \"${HEADER_MISSING_IN_NON_SINGLE_CLASS_FILE.warnText()} there are 2 declared classes and/or objects\", false),\n            rulesConfigList = rulesConfigList\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.HEADER_WRONG_FORMAT)\n    fun `header KDoc should have newline after it`() {\n        lintMethod(\n            \"\"\"\n               |$copyrightBlock\n               |/**\n               | * Very useful description\n               | * foo bar baz\n               | */\n               |package com.saveourtool.diktat.example\n               |\n               |class Example { }\n            \"\"\".trimMargin(),\n            DiktatError(4, 1, ruleId, \"${HEADER_WRONG_FORMAT.warnText()} header KDoc should have a new line after\", true),\n            rulesConfigList = rulesConfigList\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.HEADER_NOT_BEFORE_PACKAGE)\n    fun `header KDoc should be placed before package and imports`() {\n        lintMethod(\n            \"\"\"\n                |package com.saveourtool.diktat.example\n                |\n                |import com.saveourtool.diktat.example.Foo\n                |\n                |/**\n                | * This is a code snippet for tests\n                | */\n                |\n                |/**\n                | * This is an example class\n                | */\n                |class Example { }\n            \"\"\".trimMargin(),\n            DiktatError(5, 1, ruleId, \"${HEADER_NOT_BEFORE_PACKAGE.warnText()} header KDoc is located after package or imports\", true),\n            rulesConfigList = emptyList()\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.HEADER_NOT_BEFORE_PACKAGE)\n    fun `header KDoc object check`() {\n        lintMethod(\n            \"\"\"\n                |package com.saveourtool.diktat.example\n                |\n                |import com.saveourtool.diktat.example.Foo\n                |\n                |object TestEntry {\n                |@JvmStatic\n                |fun main(args: Array<String>) {\n                |   val properties = TestFrameworkProperties(\"com/saveourtool/diktat/test/framework/test_framework.properties\")\n                |   TestProcessingFactory(TestArgumentsReader(args, properties, javaClass.classLoader)).processTests()\n                |  }\n                |}\n            \"\"\".trimMargin(),\n            rulesConfigList = rulesConfigList\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.HEADER_NOT_BEFORE_PACKAGE)\n    fun `header KDoc object and class check`() {\n        lintMethod(\n            \"\"\"\n                |package com.saveourtool.diktat.example\n                |\n                |import com.saveourtool.diktat.example.Foo\n                |\n                |object TestEntry {\n                |@JvmStatic\n                |fun main(args: Array<String>) {\n                |   val properties = TestFrameworkProperties(\"com/saveourtool/diktat/test/framework/test_framework.properties\")\n                |   TestProcessingFactory(TestArgumentsReader(args, properties, javaClass.classLoader)).processTests()\n                |  }\n                |}\n                |\n                |class Some {}\n            \"\"\".trimMargin(),\n            DiktatError(1, 1, ruleId, \"${HEADER_MISSING_IN_NON_SINGLE_CLASS_FILE.warnText()} there are 2 declared classes and/or objects\"),\n            rulesConfigList = rulesConfigList\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.HEADER_NOT_BEFORE_PACKAGE)\n    fun `header KDoc in gradle script`(@TempDir tempDir: Path) {\n        lintMethodWithFile(\n            \"\"\"\n                |version = \"0.1.0-SNAPSHOT\"\n                |\n            \"\"\".trimMargin(),\n            tempDir = tempDir,\n            fileName = \"src/main/kotlin/com/saveourtool/diktat/builds.gradle.kts\"\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.HEADER_NOT_BEFORE_PACKAGE)\n    fun `header KDoc in kts script`(@TempDir tempDir: Path) {\n        lintMethodWithFile(\n            \"\"\"\n                |val version = \"0.1.0-SNAPSHOT\"\n                |\n            \"\"\".trimMargin(),\n            tempDir = tempDir,\n            fileName = \"src/main/kotlin/com/saveourtool/diktat/Example.kts\",\n            DiktatError(1, 1, ruleId, \"${HEADER_MISSING_IN_NON_SINGLE_CLASS_FILE.warnText()} there are 0 declared classes and/or objects\")\n        )\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/test/kotlin/com/saveourtool/diktat/ruleset/chapter2/KdocCommentsFixTest.kt",
    "content": "package com.saveourtool.diktat.ruleset.chapter2\n\nimport com.saveourtool.diktat.ruleset.rules.chapter2.kdoc.KdocComments\nimport com.saveourtool.diktat.util.FixTestBase\n\nimport generated.WarningNames\nimport org.junit.jupiter.api.Tag\nimport org.junit.jupiter.api.Tags\nimport org.junit.jupiter.api.Test\n\nclass KdocCommentsFixTest : FixTestBase(\"test/paragraph2/kdoc/\", ::KdocComments) {\n    @Test\n    @Tag(WarningNames.COMMENTED_BY_KDOC)\n    fun `check fix code block with kdoc comment`() {\n        fixAndCompare(\"KdocBlockCommentExpected.kt\", \"KdocBlockCommentTest.kt\")\n    }\n\n    @Test\n    @Tags(Tag(WarningNames.KDOC_NO_CONSTRUCTOR_PROPERTY), Tag(WarningNames.KDOC_NO_CONSTRUCTOR_PROPERTY_WITH_COMMENT), Tag(WarningNames.MISSING_KDOC_TOP_LEVEL))\n    fun `check fix without class kdoc`() {\n        fixAndCompare(\"ConstructorCommentNoKDocExpected.kt\", \"ConstructorCommentNoKDocTest.kt\")\n    }\n\n    @Test\n    @Tags(Tag(WarningNames.KDOC_NO_CONSTRUCTOR_PROPERTY), Tag(WarningNames.KDOC_NO_CONSTRUCTOR_PROPERTY_WITH_COMMENT))\n    fun `check fix with class kdoc`() {\n        fixAndCompare(\"ConstructorCommentExpected.kt\", \"ConstructorCommentTest.kt\")\n    }\n\n    @Test\n    @Tags(Tag(WarningNames.KDOC_NO_CONSTRUCTOR_PROPERTY), Tag(WarningNames.KDOC_NO_CONSTRUCTOR_PROPERTY_WITH_COMMENT))\n    fun `check fix with properties in class kdoc`() {\n        fixAndCompare(\"ConstructorCommentPropertiesExpected.kt\", \"ConstructorCommentPropertiesTest.kt\")\n    }\n\n    @Test\n    @Tags(Tag(WarningNames.KDOC_NO_CONSTRUCTOR_PROPERTY), Tag(WarningNames.KDOC_NO_CONSTRUCTOR_PROPERTY_WITH_COMMENT))\n    fun `should preserve newlines when moving comments from value parameters`() {\n        fixAndCompare(\"ConstructorCommentNewlineExpected.kt\", \"ConstructorCommentNewlineTest.kt\")\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/test/kotlin/com/saveourtool/diktat/ruleset/chapter2/KdocCommentsWarnTest.kt",
    "content": "package com.saveourtool.diktat.ruleset.chapter2\n\nimport com.saveourtool.diktat.common.config.rules.DIKTAT_RULE_SET_ID\nimport com.saveourtool.diktat.ruleset.constants.Warnings\nimport com.saveourtool.diktat.ruleset.constants.Warnings.KDOC_DUPLICATE_PROPERTY\nimport com.saveourtool.diktat.ruleset.constants.Warnings.KDOC_EXTRA_PROPERTY\nimport com.saveourtool.diktat.ruleset.constants.Warnings.KDOC_NO_CLASS_BODY_PROPERTIES_IN_HEADER\nimport com.saveourtool.diktat.ruleset.constants.Warnings.KDOC_NO_CONSTRUCTOR_PROPERTY\nimport com.saveourtool.diktat.ruleset.constants.Warnings.KDOC_NO_CONSTRUCTOR_PROPERTY_WITH_COMMENT\nimport com.saveourtool.diktat.ruleset.constants.Warnings.MISSING_KDOC_CLASS_ELEMENTS\nimport com.saveourtool.diktat.ruleset.constants.Warnings.MISSING_KDOC_TOP_LEVEL\nimport com.saveourtool.diktat.ruleset.rules.chapter2.kdoc.KdocComments\nimport com.saveourtool.diktat.util.LintTestBase\n\nimport com.saveourtool.diktat.api.DiktatError\nimport generated.WarningNames\nimport org.junit.jupiter.api.Tag\nimport org.junit.jupiter.api.Tags\nimport org.junit.jupiter.api.Test\n\n@Suppress(\"LargeClass\")\nclass KdocCommentsWarnTest : LintTestBase(::KdocComments) {\n    private val ruleId: String = \"$DIKTAT_RULE_SET_ID:${KdocComments.NAME_ID}\"\n\n    @Test\n    @Tag(WarningNames.COMMENTED_BY_KDOC)\n    fun `Should warn if kdoc comment is inside code block`() {\n        val code =\n            \"\"\"\n                    |package com.saveourtool.diktat.example\n                    |\n                    |/**\n                    |  * right place for kdoc\n                    |  */\n                    |class Example {\n                    |/**\n                    |  * right place for kdoc\n                    |  */\n                    |    fun doGood(){\n                    |        /**\n                    |         * wrong place for kdoc\n                    |         */\n                    |        1+2\n                    |        /**\n                    |         * right place for kdoc\n                    |         */\n                    |        fun prettyPrint(level: Int = 0, maxLevel: Int = -1): String {\n                    |            return \"test\"\n                    |        }\n                    |    }\n                    |}\n            \"\"\".trimMargin()\n        lintMethod(\n            code,\n            DiktatError(\n                11, 9, ruleId, \"${Warnings.COMMENTED_BY_KDOC.warnText()} Redundant asterisk in block comment: \\\\**\", true\n            )\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.MISSING_KDOC_TOP_LEVEL)\n    fun `all public classes should be documented with KDoc`() {\n        val code =\n            \"\"\"\n                class SomeGoodName {\n                    private class InternalClass {\n                    }\n                }\n\n                public open class SomeOtherGoodName {\n                }\n\n                open class SomeNewGoodName {\n                }\n\n                public class SomeOtherNewGoodName {\n                }\n\n            \"\"\".trimIndent()\n        lintMethod(\n            code,\n            DiktatError(1, 1, ruleId, \"${MISSING_KDOC_TOP_LEVEL.warnText()} SomeGoodName\"),\n            DiktatError(6, 1, ruleId, \"${MISSING_KDOC_TOP_LEVEL.warnText()} SomeOtherGoodName\"),\n            DiktatError(9, 1, ruleId, \"${MISSING_KDOC_TOP_LEVEL.warnText()} SomeNewGoodName\"),\n            DiktatError(12, 1, ruleId, \"${MISSING_KDOC_TOP_LEVEL.warnText()} SomeOtherNewGoodName\")\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.MISSING_KDOC_TOP_LEVEL)\n    fun `all internal classes should be documented with KDoc`() {\n        val code =\n            \"\"\"\n                internal class SomeGoodName {\n                }\n            \"\"\".trimIndent()\n        lintMethod(\n            code, DiktatError(\n                1, 1, ruleId, \"${MISSING_KDOC_TOP_LEVEL.warnText()} SomeGoodName\"\n            )\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.MISSING_KDOC_TOP_LEVEL)\n    fun `all internal and public functions on top-level should be documented with Kdoc`() {\n        val code =\n            \"\"\"\n                fun someGoodName() {\n                }\n\n                internal fun someGoodNameNew(): String {\n                    return \" \";\n                }\n\n                fun main() {}\n            \"\"\".trimIndent()\n        lintMethod(\n            code,\n            DiktatError(1, 1, ruleId, \"${MISSING_KDOC_TOP_LEVEL.warnText()} someGoodName\"),\n            DiktatError(4, 1, ruleId, \"${MISSING_KDOC_TOP_LEVEL.warnText()} someGoodNameNew\")\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.MISSING_KDOC_TOP_LEVEL)\n    fun `all internal and public functions on top-level should be documented with Kdoc (positive case)`() {\n        val code =\n            \"\"\"\n                private fun someGoodName() {\n                }\n            \"\"\".trimIndent()\n        lintMethod(code)\n    }\n\n    @Test\n    @Tag(WarningNames.MISSING_KDOC_TOP_LEVEL)\n    fun `positive Kdoc case with private class`() {\n        val code =\n            \"\"\"\n                private class SomeGoodName {\n                }\n            \"\"\".trimIndent()\n        lintMethod(code)\n    }\n\n    @Test\n    @Tag(WarningNames.MISSING_KDOC_CLASS_ELEMENTS)\n    fun `Kdoc should present for each class element`() {\n        val code =\n            \"\"\"\n                /**\n                * class that contains fields, functions and public subclasses\n                **/\n                class SomeGoodName {\n                    val variable: String = \"\"\n                    private val privateVariable: String = \"\"\n                    fun perfectFunction() {\n                    }\n\n                    private fun privateFunction() {\n                    }\n\n                    class InternalClass {\n                    }\n\n                    private class InternalClass {\n                    }\n\n                    public fun main() {}\n                }\n            \"\"\".trimIndent()\n        lintMethod(\n            code,\n            DiktatError(5, 5, ruleId, \"${MISSING_KDOC_CLASS_ELEMENTS.warnText()} variable\"),\n            DiktatError(7, 5, ruleId, \"${MISSING_KDOC_CLASS_ELEMENTS.warnText()} perfectFunction\"),\n            DiktatError(13, 5, ruleId, \"${MISSING_KDOC_CLASS_ELEMENTS.warnText()} InternalClass\")\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.MISSING_KDOC_CLASS_ELEMENTS)\n    fun `Kdoc shouldn't not be mandatory for overridden functions and props`() {\n        val code =\n            \"\"\"\n                /**\n                * class that contains fields, functions and public subclasses\n                **/\n                class SomeGoodName : Another {\n                    val variable: String = \"\"\n                    private val privateVariable: String = \"\"\n                    override val someVal: String = \"\"\n                    fun perfectFunction() {\n                    }\n\n                    override fun overrideFunction() {\n                    }\n\n                    class InternalClass {\n                    }\n\n                    private class InternalClass {\n                    }\n\n                    public fun main() {}\n                }\n            \"\"\".trimIndent()\n        lintMethod(\n            code,\n            DiktatError(5, 5, ruleId, \"${MISSING_KDOC_CLASS_ELEMENTS.warnText()} variable\"),\n            DiktatError(8, 5, ruleId, \"${MISSING_KDOC_CLASS_ELEMENTS.warnText()} perfectFunction\"),\n            DiktatError(14, 5, ruleId, \"${MISSING_KDOC_CLASS_ELEMENTS.warnText()} InternalClass\")\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.MISSING_KDOC_CLASS_ELEMENTS)\n    fun `Kdoc shouldn't present for each class element because Test annotation`() {\n        lintMethod(\n            \"\"\"\n                    /**\n                    * class that contains fields, functions and public subclasses\n                    **/\n                    @Test\n                    class SomeGoodName {\n                        val variable: String = \"\"\n                        private val privateVariable: String = \"\"\n                        fun perfectFunction() {\n                        }\n\n                        private fun privateFunction() {\n                        }\n\n                        class InternalClass {\n                        }\n\n                        private class InternalClass {\n                        }\n                    }\n            \"\"\".trimIndent()\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.MISSING_KDOC_CLASS_ELEMENTS)\n    fun `Kdoc should present for each class element (positive)`() {\n        val code =\n            \"\"\"\n                /**\n                * class that contains fields, functions and public subclasses\n                **/\n                class SomeGoodName {\n                    /**\n                    * class that contains fields, functions and public subclasses\n                    **/\n                    val variable: String = \"\"\n\n                    private val privateVariable: String = \"\"\n\n                    /**\n                    * class that contains fields, functions and public subclasses\n                    **/\n                    fun perfectFunction() {\n                    }\n\n                    private fun privateFunction() {\n                    }\n\n                    /**\n                    * class that contains fields, functions and public subclasses\n                    **/\n                    class InternalClass {\n                    }\n\n                    private class InternalClass {\n                    }\n                }\n            \"\"\".trimIndent()\n        lintMethod(code)\n    }\n\n    @Test\n    @Tag(WarningNames.MISSING_KDOC_CLASS_ELEMENTS)\n    fun `regression - should not force documentation on standard methods`() {\n        lintMethod(\n            \"\"\"\n                    |/**\n                    | * This is an example class\n                    | */\n                    |class Example {\n                    |    override fun toString() = \"\"\n                    |}\n            \"\"\".trimMargin()\n        )\n    }\n\n    @Test\n    @Tags(Tag(WarningNames.KDOC_NO_CONSTRUCTOR_PROPERTY_WITH_COMMENT), Tag(WarningNames.KDOC_EXTRA_PROPERTY))\n    fun `check simple primary constructor with comment`() {\n        lintMethod(\n            \"\"\"\n                    |/**\n                    | * @property name d\n                    | * @param adsf\n                    | * @return something\n                    | */\n                    |class Example constructor (\n                    |   // short\n                    |   val name: String\n                    |) {\n                    |}\n            \"\"\".trimMargin(),\n            DiktatError(3, 4, ruleId, \"${KDOC_EXTRA_PROPERTY.warnText()} @param adsf\", false),\n            DiktatError(7, 4, ruleId, \"${KDOC_NO_CONSTRUCTOR_PROPERTY_WITH_COMMENT.warnText()} add comment for property <name> to KDoc\", true)\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.KDOC_NO_CONSTRUCTOR_PROPERTY)\n    fun `should trigger on override parameter`() {\n        lintMethod(\n            \"\"\"\n                    |@Suppress(\"MISSING_KDOC_TOP_LEVEL\")\n                    |public class Example (\n                    |   override val serializersModule: SerializersModule = EmptySerializersModule\n                    |)\n            \"\"\".trimMargin(),\n            DiktatError(3, 4, ruleId, \"${KDOC_NO_CONSTRUCTOR_PROPERTY.warnText()} add property <serializersModule> to KDoc\", true)\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.KDOC_NO_CONSTRUCTOR_PROPERTY_WITH_COMMENT)\n    fun `shouldn't trigger because not primary constructor`() {\n        lintMethod(\n            \"\"\"\n                    |/**\n                    | * @property name d\n                    | * @property anotherName text\n                    | */\n                    |class Example {\n                    |   constructor(\n                    |   // name\n                    |   name: String,\n                    |   anotherName: String,\n                    |   oneMoreName: String\n                    |   )\n                    |}\n            \"\"\".trimMargin()\n        )\n    }\n\n    @Test\n    @Tags(Tag(WarningNames.KDOC_NO_CONSTRUCTOR_PROPERTY_WITH_COMMENT), Tag(WarningNames.KDOC_NO_CONSTRUCTOR_PROPERTY))\n    fun `check constructor with comment`() {\n        lintMethod(\n            \"\"\"\n                    |/**\n                    | * @return some\n                    | */\n                    |class Example (\n                    |   //some descriptions\n                    |   val name: String,\n                    |   anotherName: String,\n                    |   oneMoreName: String\n                    |   ) {\n                    |}\n            \"\"\".trimMargin(),\n            DiktatError(5, 4, ruleId, \"${KDOC_NO_CONSTRUCTOR_PROPERTY_WITH_COMMENT.warnText()} add comment for property <name> to KDoc\", true),\n            DiktatError(7, 4, ruleId, \"${KDOC_NO_CONSTRUCTOR_PROPERTY.warnText()} add param <anotherName> to KDoc\", true),\n            DiktatError(8, 4, ruleId, \"${KDOC_NO_CONSTRUCTOR_PROPERTY.warnText()} add param <oneMoreName> to KDoc\", true)\n        )\n    }\n\n    @Test\n    @Tags(Tag(WarningNames.KDOC_NO_CONSTRUCTOR_PROPERTY_WITH_COMMENT), Tag(WarningNames.KDOC_NO_CONSTRUCTOR_PROPERTY))\n    fun `check constructor with block comment`() {\n        lintMethod(\n            \"\"\"\n                    |/**\n                    | * @return some\n                    | */\n                    |class Example (\n                    |   /*some descriptions*/val name: String,\n                    |   anotherName: String,\n                    |   private val oneMoreName: String\n                    |   ) {\n                    |}\n            \"\"\".trimMargin(),\n            DiktatError(5, 4, ruleId, \"${KDOC_NO_CONSTRUCTOR_PROPERTY_WITH_COMMENT.warnText()} add comment for property <name> to KDoc\", true),\n            DiktatError(6, 4, ruleId, \"${KDOC_NO_CONSTRUCTOR_PROPERTY.warnText()} add param <anotherName> to KDoc\", true),\n            DiktatError(7, 4, ruleId, \"${KDOC_NO_CONSTRUCTOR_PROPERTY.warnText()} add param <oneMoreName> to KDoc\", true)\n        )\n    }\n\n    @Test\n    @Tags(Tag(WarningNames.KDOC_NO_CONSTRUCTOR_PROPERTY_WITH_COMMENT), Tag(WarningNames.KDOC_NO_CONSTRUCTOR_PROPERTY))\n    fun `check not property but params`() {\n        lintMethod(\n            \"\"\"\n                    |/**\n                    | * @return some\n                    | */\n                    |class Example (\n                    |   //some descriptions\n                    |   private val name: String,\n                    |   anotherName: String,\n                    |   private val oneMoreName: String\n                    |   ) {\n                    |}\n            \"\"\".trimMargin(),\n            DiktatError(5, 4, ruleId, \"${KDOC_NO_CONSTRUCTOR_PROPERTY_WITH_COMMENT.warnText()} add comment for param <name> to KDoc\", true),\n            DiktatError(7, 4, ruleId, \"${KDOC_NO_CONSTRUCTOR_PROPERTY.warnText()} add param <anotherName> to KDoc\", true),\n            DiktatError(8, 4, ruleId, \"${KDOC_NO_CONSTRUCTOR_PROPERTY.warnText()} add param <oneMoreName> to KDoc\", true)\n        )\n    }\n\n    @Test\n    @Tags(Tag(WarningNames.KDOC_NO_CONSTRUCTOR_PROPERTY_WITH_COMMENT), Tag(WarningNames.KDOC_NO_CONSTRUCTOR_PROPERTY))\n    fun `check constructor with kdoc`() {\n        lintMethod(\n            \"\"\"\n                    |/**\n                    | * @return some\n                    | */\n                    |class Example (\n                    |   /**\n                    |    * some descriptions\n                    |    */\n                    |   val name: String,\n                    |   anotherName: String,\n                    |   private val oneMoreName: String\n                    |   ) {\n                    |}\n            \"\"\".trimMargin(),\n            DiktatError(5, 4, ruleId, \"${KDOC_NO_CONSTRUCTOR_PROPERTY_WITH_COMMENT.warnText()} add comment for property <name> to KDoc\", true),\n            DiktatError(9, 4, ruleId, \"${KDOC_NO_CONSTRUCTOR_PROPERTY.warnText()} add param <anotherName> to KDoc\", true),\n            DiktatError(10, 4, ruleId, \"${KDOC_NO_CONSTRUCTOR_PROPERTY.warnText()} add param <oneMoreName> to KDoc\", true)\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.KDOC_NO_CONSTRUCTOR_PROPERTY_WITH_COMMENT)\n    fun `shouldn't fix because KDoc comment and property tag inside`() {\n        lintMethod(\n            \"\"\"\n                    |/**\n                    | * @return some\n                    | */\n                    |class Example (\n                    |   /**\n                    |    * sdcjkh\n                    |    * @property name text2\n                    |    * fdfdfd\n                    |    */\n                    |   val name: String,\n                    |   ) {\n                    |}\n            \"\"\".trimMargin(),\n            DiktatError(5, 4, ruleId, \"${KDOC_NO_CONSTRUCTOR_PROPERTY_WITH_COMMENT.warnText()} add comment for property <name> to KDoc\", false)\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.KDOC_NO_CONSTRUCTOR_PROPERTY_WITH_COMMENT)\n    fun `shouldn't fix because KDoc comment and any tag inside`() {\n        lintMethod(\n            \"\"\"\n                    |/**\n                    | * @return some\n                    | */\n                    |class Example (\n                    |   /**\n                    |    * sdcjkh\n                    |    * @return name text2\n                    |    * fdfdfd\n                    |    */\n                    |   val name: String,\n                    |   ) {\n                    |}\n            \"\"\".trimMargin(),\n            DiktatError(5, 4, ruleId, \"${KDOC_NO_CONSTRUCTOR_PROPERTY_WITH_COMMENT.warnText()} add comment for property <name> to KDoc\", false)\n        )\n    }\n\n    @Test\n    @Tags(Tag(WarningNames.KDOC_NO_CONSTRUCTOR_PROPERTY), Tag(WarningNames.KDOC_EXTRA_PROPERTY))\n    fun `no property kdoc`() {\n        lintMethod(\n            \"\"\"\n                    |/**\n                    | * @property Name text\n                    | */\n                    |class Example (\n                    |   val name: String,\n                    |   ) {\n                    |}\n            \"\"\".trimMargin(),\n            DiktatError(2, 4, ruleId, \"${KDOC_EXTRA_PROPERTY.warnText()} @property Name text\", false),\n            DiktatError(5, 4, ruleId, \"${KDOC_NO_CONSTRUCTOR_PROPERTY.warnText()} add property <name> to KDoc\", true)\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.KDOC_EXTRA_PROPERTY)\n    fun `extra property in kdoc`() {\n        lintMethod(\n            \"\"\"\n                    |/**\n                    | * @property name bla\n                    | * @property kek\n                    | */\n                    |class Example (\n                    |   val name: String\n                    |   ) {\n                    |}\n            \"\"\".trimMargin(),\n            DiktatError(3, 4, ruleId, \"${KDOC_EXTRA_PROPERTY.warnText()} @property kek\", false)\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.KDOC_NO_CONSTRUCTOR_PROPERTY)\n    fun `change property to param in kdoc for private parameter`() {\n        lintMethod(\n            \"\"\"\n                    |/**\n                    | * @property name abc\n                    | */\n                    |class Example (\n                    |   private val name: String,\n                    |   ) {\n                    |}\n            \"\"\".trimMargin(),\n            DiktatError(5, 4, ruleId, \"${KDOC_NO_CONSTRUCTOR_PROPERTY.warnText()} change `@property` tag to `@param` tag for <name> to KDoc\", true)\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.KDOC_NO_CONSTRUCTOR_PROPERTY)\n    fun `change param to property in kdoc for property`() {\n        lintMethod(\n            \"\"\"\n                    |/**\n                    | * @param name abc\n                    | */\n                    |class Example (\n                    |   val name: String,\n                    |   ) {\n                    |}\n            \"\"\".trimMargin(),\n            DiktatError(5, 4, ruleId, \"${KDOC_NO_CONSTRUCTOR_PROPERTY.warnText()} change `@param` tag to `@property` tag for <name> to KDoc\", true),\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.KDOC_NO_CONSTRUCTOR_PROPERTY_WITH_COMMENT)\n    fun `change param to property in kdoc for property with single comment`() {\n        lintMethod(\n            \"\"\"\n                    |/**\n                    | * @param name abc\n                    | */\n                    |class Example (\n                    |   //some descriptions\n                    |   val name: String,\n                    |   ) {\n                    |}\n            \"\"\".trimMargin(),\n            DiktatError(5, 4, ruleId, \"${KDOC_NO_CONSTRUCTOR_PROPERTY_WITH_COMMENT.warnText()} change `@param` tag to `@property` tag for <name> and add comment to KDoc\", true),\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.KDOC_NO_CONSTRUCTOR_PROPERTY_WITH_COMMENT)\n    fun `change param to property in kdoc for property with block comment`() {\n        lintMethod(\n            \"\"\"\n                    |/**\n                    | * @param name abc\n                    | */\n                    |class Example (\n                    |   /*some descriptions*/\n                    |   val name: String,\n                    |   ) {\n                    |}\n            \"\"\".trimMargin(),\n            DiktatError(5, 4, ruleId, \"${KDOC_NO_CONSTRUCTOR_PROPERTY_WITH_COMMENT.warnText()} change `@param` tag to `@property` tag for <name> and add comment to KDoc\", true),\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.KDOC_NO_CONSTRUCTOR_PROPERTY_WITH_COMMENT)\n    fun `comment on private parameter`() {\n        lintMethod(\n            \"\"\"\n                    |/**\n                    | * abc\n                    | */\n                    |class Example (\n                    |   // single-line comment\n                    |   private val name: String,\n                    |   ) {\n                    |}\n            \"\"\".trimMargin(),\n            DiktatError(5, 4, ruleId,\"${KDOC_NO_CONSTRUCTOR_PROPERTY_WITH_COMMENT.warnText()} add comment for param <name> to KDoc\", true)\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.KDOC_NO_CONSTRUCTOR_PROPERTY)\n    fun `should trigger on private parameter`() {\n        lintMethod(\n            \"\"\"\n                    |/**\n                    | * text\n                    | */\n                    |class Example (\n                    |   private val name: String,\n                    |   ) {\n                    |}\n            \"\"\".trimMargin(),\n            DiktatError(5, 4, ruleId,\"${KDOC_NO_CONSTRUCTOR_PROPERTY.warnText()} add param <name> to KDoc\", true)\n        )\n    }\n\n    @Test\n    @Tags(Tag(WarningNames.KDOC_NO_CONSTRUCTOR_PROPERTY), Tag(WarningNames.MISSING_KDOC_TOP_LEVEL))\n    fun `no property kdoc and class`() {\n        lintMethod(\n            \"\"\"\n                    |class Example (\n                    |   val name: String,\n                    |   private val surname: String\n                    |   ) {\n                    |}\n            \"\"\".trimMargin(),\n            DiktatError(1, 1, ruleId, \"${MISSING_KDOC_TOP_LEVEL.warnText()} Example\"),\n            DiktatError(2, 4, ruleId, \"${KDOC_NO_CONSTRUCTOR_PROPERTY.warnText()} add property <name> to KDoc\", true),\n            DiktatError(3, 4, ruleId, \"${KDOC_NO_CONSTRUCTOR_PROPERTY.warnText()} add param <surname> to KDoc\", true)\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.KDOC_NO_CLASS_BODY_PROPERTIES_IN_HEADER)\n    fun `property described only in class KDoc`() {\n        lintMethod(\n            \"\"\"\n                |/**\n                | * @property foo lorem ipsum\n                | */\n                |class Example {\n                |    val foo: Any\n                |}\n            \"\"\".trimMargin(),\n            DiktatError(5, 5, ruleId, \"${KDOC_NO_CLASS_BODY_PROPERTIES_IN_HEADER.warnText()} val foo: Any\")\n        )\n    }\n\n    @Test\n    fun `property described both in class KDoc and own KDoc`() {\n        lintMethod(\n            \"\"\"\n                |/**\n                | * @property foo lorem ipsum\n                | */\n                |class Example {\n                |    /**\n                |     * dolor sit amet\n                |     */\n                |    val foo: Any\n                |}\n            \"\"\".trimMargin(),\n            DiktatError(5, 5, ruleId, \"${KDOC_NO_CLASS_BODY_PROPERTIES_IN_HEADER.warnText()} /**...\")\n        )\n    }\n\n    @Test\n    fun `shouldn't trigger kdoc top level on actual methods`() {\n        lintMethod(\n            \"\"\"\n                |actual fun foo() {}\n                |expect fun fo() {}\n                |internal actual fun foo() {}\n                |internal expect fun foo() {}\n                |\n                |expect class B{}\n                |\n                |actual class A{}\n            \"\"\".trimMargin(),\n            DiktatError(2, 1, ruleId, \"${MISSING_KDOC_TOP_LEVEL.warnText()} fo\"),\n            DiktatError(4, 1, ruleId, \"${MISSING_KDOC_TOP_LEVEL.warnText()} foo\"),\n            DiktatError(6, 1, ruleId, \"${MISSING_KDOC_TOP_LEVEL.warnText()} B\")\n        )\n    }\n\n    @Test\n    fun `should find Kdoc after annotation of function`() {\n        lintMethod(\n            \"\"\"\n                |@SomeAnnotation\n                |/**\n                | * Just print a string\n                | *\n                | * @param f string to print\n                | * @return 1\n                | */\n                |internal fun prnt(f: String) {\n                |   println(f)\n                |   return 1\n                |}\n            \"\"\".trimMargin()\n        )\n    }\n\n    @Test\n    fun `should find Kdoc after annotation of class`() {\n        lintMethod(\n            \"\"\"\n                |@SomeAnnotation\n                |/**\n                | * Test class\n                | */\n                |class example {\n                |\n                |}\n            \"\"\".trimMargin()\n        )\n    }\n\n    @Test\n    fun `should find Kdoc inside a modifier list`() {\n        lintMethod(\n            \"\"\"\n                |public\n                |/**\n                | * foo\n                | */\n                |actual fun foo() { }\n            \"\"\".trimMargin()\n        )\n    }\n\n    @Test\n    fun `should warn if there are duplicate tags 1`() {\n        lintMethod(\n            \"\"\"\n                |/**\n                | * @param field1 description1\n                | * @param field2 description2\n                | * @param field2\n                | */\n                |fun foo(field1: Long, field2: Int) {\n                |    //\n                |}\n            \"\"\".trimMargin(),\n            DiktatError(4, 4, ruleId, \"${KDOC_DUPLICATE_PROPERTY.warnText()} @param field2\"),\n        )\n    }\n\n    @Test\n    fun `should warn if there are duplicate tags 2`() {\n        lintMethod(\n            \"\"\"\n                |/**\n                | * @property field1\n                | * @property field2\n                | * @property field2\n                | */\n                |@Serializable\n                |data class DataClass(\n                |    val field1: String,\n                |    val field2: String,\n                |)\n            \"\"\".trimMargin(),\n            DiktatError(4, 4, ruleId, \"${KDOC_DUPLICATE_PROPERTY.warnText()} @property field2\"),\n        )\n    }\n\n    @Test\n    fun `should warn if there are duplicate tags 3`() {\n        lintMethod(\n            \"\"\"\n                |/**\n                | * @property field1\n                | * @property field2\n                | * @param field2\n                | */\n                |@Serializable\n                |data class DataClass(\n                |    val field1: String,\n                |    val field2: String,\n                |)\n            \"\"\".trimMargin(),\n            DiktatError(4, 4, ruleId, \"${KDOC_DUPLICATE_PROPERTY.warnText()} @param field2\"),\n        )\n    }\n\n    @Test\n    fun `should warn if there are duplicate tags 4`() {\n        lintMethod(\n            \"\"\"\n                |/**\n                | * @property field1\n                | * @property field1\n                | * @property field2\n                | * @param field2\n                | */\n                |@Serializable\n                |data class DataClass(\n                |    val field1: String,\n                |    val field2: String,\n                |)\n            \"\"\".trimMargin(),\n            DiktatError(3, 4, ruleId, \"${KDOC_DUPLICATE_PROPERTY.warnText()} @property field1\"),\n            DiktatError(5, 4, ruleId, \"${KDOC_DUPLICATE_PROPERTY.warnText()} @param field2\"),\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.KDOC_EXTRA_PROPERTY)\n    fun `shouldn't warn extra property on generic type`() {\n        lintMethod(\n            \"\"\"\n                |/**\n                | * S3 implementation of Storage\n                | *\n                | * @param s3Operations [S3Operations] to operate with S3\n                | * @param K type of key\n                | */\n                |abstract class AbstractReactiveStorage<K : Any> constructor(\n                |    s3Operations: S3Operations,\n                |) : ReactiveStorage<K> {\n                |  // abcd\n                |}\n            \"\"\".trimMargin()\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.KDOC_NO_CONSTRUCTOR_PROPERTY)\n    fun `should trigger on generic type`() {\n        lintMethod(\n            \"\"\"\n                |/**\n                | * S3 implementation of Storage\n                | *\n                | * @param s3Operations [S3Operations] to operate with S3\n                | */\n                |abstract class AbstractReactiveStorage<K : Any, P: Any>(\n                |    s3Operations: S3Operations,\n                |) : ReactiveStorage<K>, AnotherStorage<P> {\n                |  // abcd\n                |}\n            \"\"\".trimMargin(),\n            DiktatError(6, 40, ruleId, \"${KDOC_NO_CONSTRUCTOR_PROPERTY.warnText()} add param <K> to KDoc\", true),\n            DiktatError(6, 49, ruleId, \"${KDOC_NO_CONSTRUCTOR_PROPERTY.warnText()} add param <P> to KDoc\", true),\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.KDOC_NO_CONSTRUCTOR_PROPERTY)\n    fun `change property to param in kdoc for generic type`() {\n        lintMethod(\n            \"\"\"\n                |/**\n                | * S3 implementation of Storage\n                | *\n                | * @param s3Operations [S3Operations] to operate with S3\n                | * @property K type of key\n                | */\n                |abstract class AbstractReactiveStorage<K : Any, P: Any>(\n                |    s3Operations: S3Operations,\n                |) : ReactiveStorage<K>, AnotherStorage<P> {\n                |  // abcd\n                |}\n            \"\"\".trimMargin(),\n            DiktatError(7, 40, ruleId, \"${KDOC_NO_CONSTRUCTOR_PROPERTY.warnText()} change `@property` tag to `@param` tag for <K> to KDoc\", true),\n            DiktatError(7, 49, ruleId, \"${KDOC_NO_CONSTRUCTOR_PROPERTY.warnText()} add param <P> to KDoc\", true),\n        )\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/test/kotlin/com/saveourtool/diktat/ruleset/chapter2/KdocFormattingFixTest.kt",
    "content": "package com.saveourtool.diktat.ruleset.chapter2\n\nimport com.saveourtool.diktat.ruleset.rules.chapter2.kdoc.KdocFormatting\nimport com.saveourtool.diktat.util.FixTestBase\n\nimport generated.WarningNames\nimport org.junit.jupiter.api.Tag\nimport org.junit.jupiter.api.Tags\nimport org.junit.jupiter.api.Test\n\nclass KdocFormattingFixTest : FixTestBase(\"test/paragraph2/kdoc/\", ::KdocFormatting) {\n    @Test\n    @Tag(WarningNames.KDOC_WRONG_SPACES_AFTER_TAG)\n    fun `there should be exactly one white space after tag name`() {\n        fixAndCompare(\"SpacesAfterTagExpected.kt\", \"SpacesAfterTagTest.kt\")\n    }\n\n    @Test\n    @Tag(WarningNames.KDOC_WRONG_TAGS_ORDER)\n    fun `basic tags should be ordered in KDocs`() {\n        fixAndCompare(\"OrderedTagsExpected.kt\", \"OrderedTagsTest.kt\")\n    }\n\n    @Test\n    @Tag(WarningNames.KDOC_WRONG_TAGS_ORDER)\n    fun `extra new line with tags ordering should not cause assert`() {\n        fixAndCompare(\"OrderedTagsAssertionExpected.kt\", \"OrderedTagsAssertionTest.kt\")\n    }\n\n    @Test\n    @Tag(WarningNames.KDOC_NO_NEWLINES_BETWEEN_BASIC_TAGS)\n    fun `basic tags should not have empty lines between`() {\n        fixAndCompare(\"BasicTagsEmptyLinesExpected.kt\", \"BasicTagsEmptyLinesTest.kt\")\n    }\n\n    @Test\n    @Tag(WarningNames.KDOC_NO_NEWLINE_AFTER_SPECIAL_TAGS)\n    fun `special tags should have newline after them`() {\n        fixAndCompare(\"SpecialTagsInKdocExpected.kt\", \"SpecialTagsInKdocTest.kt\")\n    }\n\n    @Test\n    @Tag(WarningNames.KDOC_NO_DEPRECATED_TAG)\n    fun `@deprecated tag should be substituted with annotation`() {\n        fixAndCompare(\"DeprecatedTagExpected.kt\", \"DeprecatedTagTest.kt\")\n    }\n\n    @Test\n    @Tag(WarningNames.KDOC_NEWLINES_BEFORE_BASIC_TAGS)\n    fun `Empty line should be added before block of standard tags`() {\n        fixAndCompare(\"BasicTagsEmptyLineBeforeExpected.kt\", \"BasicTagsEmptyLineBeforeTest.kt\")\n    }\n\n    @Test\n    @Tags(Tag(WarningNames.KDOC_NO_DEPRECATED_TAG), Tag(WarningNames.KDOC_NO_NEWLINES_BETWEEN_BASIC_TAGS))\n    fun `KdocFormatting - all warnings`() {\n        fixAndCompare(\"KdocFormattingFullExpected.kt\", \"KdocFormattingFullTest.kt\")\n    }\n\n    @Test\n    @Tags(Tag(WarningNames.KDOC_NO_DEPRECATED_TAG), Tag(WarningNames.KDOC_NO_NEWLINES_BETWEEN_BASIC_TAGS))\n    fun `KdocFormatting - sort order`() {\n        fixAndCompare(\"KdocFormattingOrderExpected.kt\", \"KdocFormattingOrderTest.kt\")\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/test/kotlin/com/saveourtool/diktat/ruleset/chapter2/KdocFormattingTest.kt",
    "content": "package com.saveourtool.diktat.ruleset.chapter2\n\nimport com.saveourtool.diktat.common.config.rules.DIKTAT_RULE_SET_ID\nimport com.saveourtool.diktat.common.config.rules.RulesConfig\nimport com.saveourtool.diktat.ruleset.constants.Warnings\nimport com.saveourtool.diktat.ruleset.constants.Warnings.KDOC_EMPTY_KDOC\nimport com.saveourtool.diktat.ruleset.constants.Warnings.KDOC_NEWLINES_BEFORE_BASIC_TAGS\nimport com.saveourtool.diktat.ruleset.constants.Warnings.KDOC_NO_DEPRECATED_TAG\nimport com.saveourtool.diktat.ruleset.constants.Warnings.KDOC_NO_EMPTY_TAGS\nimport com.saveourtool.diktat.ruleset.constants.Warnings.KDOC_NO_NEWLINES_BETWEEN_BASIC_TAGS\nimport com.saveourtool.diktat.ruleset.constants.Warnings.KDOC_NO_NEWLINE_AFTER_SPECIAL_TAGS\nimport com.saveourtool.diktat.ruleset.constants.Warnings.KDOC_WRONG_SPACES_AFTER_TAG\nimport com.saveourtool.diktat.ruleset.constants.Warnings.KDOC_WRONG_TAGS_ORDER\nimport com.saveourtool.diktat.ruleset.rules.chapter2.kdoc.KdocFormatting\nimport com.saveourtool.diktat.util.LintTestBase\n\nimport com.saveourtool.diktat.api.DiktatError\nimport generated.WarningNames\nimport org.junit.jupiter.api.Tag\nimport org.junit.jupiter.api.Test\n\nclass KdocFormattingTest : LintTestBase(::KdocFormatting) {\n    private val ruleId: String = \"$DIKTAT_RULE_SET_ID:${KdocFormatting.NAME_ID}\"\n    private val funCode = \"\"\"\n         fun foo(a: Int): Int {\n             if (false) throw IllegalStateException()\n             return 2 * a\n         }\n    \"\"\".trimIndent()\n\n    @Test\n    @Tag(WarningNames.KDOC_EMPTY_KDOC)\n    fun `empty KDocs are not allowed - example with empty KDOC_SECTION`() {\n        lintMethod(\n            \"\"\"/**\n               | *${\" \".repeat(5)}\n               | */\n               |fun foo() = Unit\n            \"\"\".trimMargin(),\n            DiktatError(1, 1, ruleId, \"${KDOC_EMPTY_KDOC.warnText()} foo\", false)\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.KDOC_EMPTY_KDOC)\n    fun `empty KDocs are not allowed - example with no KDOC_SECTION`() {\n        lintMethod(\n            \"\"\"/**\n               | */\n               |fun foo() = Unit\n            \"\"\".trimMargin(),\n            DiktatError(1, 1, ruleId, \"${KDOC_EMPTY_KDOC.warnText()} foo\", false)\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.KDOC_EMPTY_KDOC)\n    fun `empty KDocs are not allowed - without bound identifier`() {\n        lintMethod(\n            \"\"\"/**\n               | *\n               | */\n            \"\"\".trimMargin(),\n            DiktatError(1, 1, ruleId, \"${KDOC_EMPTY_KDOC.warnText()} /**...\", false)\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.KDOC_EMPTY_KDOC)\n    fun `empty KDocs are not allowed - with anonymous entity`() {\n        lintMethod(\n            \"\"\"class Example {\n               |    /**\n               |      *\n               |      */\n               |    companion object { }\n               |}\n            \"\"\".trimMargin(),\n            DiktatError(2, 5, ruleId, \"${KDOC_EMPTY_KDOC.warnText()} object\", false)\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.KDOC_NO_DEPRECATED_TAG)\n    fun `@deprecated tag is not allowed`() {\n        val invalidCode = \"\"\"\n            /**\n             * @deprecated use foo instead\n             */\n            fun bar() = Unit\n        \"\"\".trimIndent()\n\n        lintMethod(invalidCode,\n            DiktatError(2, 4, ruleId, \"${KDOC_NO_DEPRECATED_TAG.warnText()} @deprecated use foo instead\", true)\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.KDOC_NO_EMPTY_TAGS)\n    fun `no empty descriptions in tag blocks are allowed`() {\n        val invalidCode = \"\"\"\n            /**\n             * @param a\n             * @return\n             * @throws IllegalStateException\n             */\n             $funCode\n        \"\"\".trimIndent()\n\n        lintMethod(invalidCode,\n            DiktatError(3, 16, ruleId,\n                \"${KDOC_NO_EMPTY_TAGS.warnText()} @return\", false))\n    }\n\n    @Test\n    fun `KDocs should contain only one white space between tag and its content (positive example)`() {\n        val validCode = \"\"\"\n            /**\n             * @param a dummy int\n             * @return doubled value\n             * @throws IllegalStateException\n             */\n             $funCode\n        \"\"\".trimIndent()\n\n        lintMethod(validCode)\n    }\n\n    @Test\n    @Tag(WarningNames.KDOC_WRONG_SPACES_AFTER_TAG)\n    fun `KDocs should contain only one white space between tag and its content`() {\n        val invalidCode = \"\"\"\n            /**\n             * @param  a dummy int\n             * @param b   dummy int\n             * @return  doubled value\n             * @throws${'\\t'}IllegalStateException\n             */\n             $funCode\n        \"\"\".trimIndent()\n\n        lintMethod(invalidCode,\n            DiktatError(2, 16, ruleId,\n                \"${KDOC_WRONG_SPACES_AFTER_TAG.warnText()} @param\", true),\n            DiktatError(3, 16, ruleId,\n                \"${KDOC_WRONG_SPACES_AFTER_TAG.warnText()} @param\", true),\n            DiktatError(4, 16, ruleId,\n                \"${KDOC_WRONG_SPACES_AFTER_TAG.warnText()} @return\", true),\n            DiktatError(5, 16, ruleId,\n                \"${KDOC_WRONG_SPACES_AFTER_TAG.warnText()} @throws\", true))\n    }\n\n    @Test\n    @Tag(WarningNames.KDOC_WRONG_SPACES_AFTER_TAG)\n    fun `check end of the line after tag isn't error`() {\n        val invalidCode = \"\"\"\n            /**\n             * @implNote\n             * implNote text\n             *\n             * @param a dummy int\n             * @param b dummy int\n             * @return doubled value\n             * @throws IllegalStateException\n             */\n             $funCode\n        \"\"\".trimIndent()\n        lintMethod(invalidCode)\n    }\n\n    @Test\n    @Tag(WarningNames.KDOC_WRONG_TAGS_ORDER)\n    fun `tags should be ordered in KDocs (positive example)`() {\n        val validCode = \"\"\"\n            /**\n             * @param a dummy int\n             * @return doubled value\n             * @throws IllegalStateException\n             */\n             $funCode\n        \"\"\".trimIndent()\n\n        lintMethod(validCode)\n    }\n\n    @Test\n    @Tag(WarningNames.KDOC_WRONG_TAGS_ORDER)\n    fun `tags should be ordered in KDocs`() {\n        val invalidCode = \"\"\"\n            /**\n             * @return doubled value\n             * @throws IllegalStateException\n             * @param a dummy int\n             */\n             $funCode\n        \"\"\".trimIndent()\n\n        lintMethod(invalidCode,\n            DiktatError(2, 16, ruleId,\n                \"${KDOC_WRONG_TAGS_ORDER.warnText()} @return, @throws, @param\", true))\n    }\n\n    @Test\n    @Tag(WarningNames.KDOC_WRONG_TAGS_ORDER)\n    fun `tags should be ordered assertion issue`() {\n        val invalidCode = \"\"\"\n            /**\n             * Reporter that produces a JSON report as a [Report]\n             *\n             * @property out a sink for output\n             *\n             * @param builder additional configuration lambda for serializers module\n             */\n            class JsonReporter(\n                override val out: BufferedSink,\n                builder: PolymorphicModuleBuilder<Plugin.TestFiles>.() -> Unit = {}\n            ) : Reporter\n        \"\"\".trimIndent()\n\n        lintMethod(invalidCode,\n            DiktatError(4, 4, ruleId,\n                \"${KDOC_NO_NEWLINES_BETWEEN_BASIC_TAGS.warnText()} @property\", true),\n            DiktatError(4, 4, ruleId,\n                \"${KDOC_WRONG_TAGS_ORDER.warnText()} @property, @param\", true)\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.KDOC_NO_NEWLINES_BETWEEN_BASIC_TAGS)\n    fun `newlines are not allowed between basic tags`() {\n        val invalidCode = \"\"\"\n            /**\n             * @param a dummy int\n             *\n             * @return doubled value\n\n             * @throws IllegalStateException\n             */\n             $funCode\n        \"\"\".trimIndent()\n\n        lintMethod(invalidCode,\n            DiktatError(2, 16, ruleId,\n                \"${KDOC_NO_NEWLINES_BETWEEN_BASIC_TAGS.warnText()} @param\", true),\n            DiktatError(4, 16, ruleId,\n                \"${KDOC_NO_NEWLINES_BETWEEN_BASIC_TAGS.warnText()} @return\", true))\n    }\n\n    @Test\n    @Tag(WarningNames.KDOC_NEWLINES_BEFORE_BASIC_TAGS)\n    fun `basic tags block should have empty line before if there is other KDoc content (positive example)`() {\n        lintMethod(\n            \"\"\"/**\n               | * Lorem ipsum\n               | * dolor sit amet\n               | *\n               | * @param a integer parameter\n               | */\n               |fun test(a: Int): Unit = Unit\n            \"\"\".trimMargin()\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.KDOC_NEWLINES_BEFORE_BASIC_TAGS)\n    fun `basic tags block shouldn't have empty line before if there is no other KDoc content`() {\n        lintMethod(\n            \"\"\"/**\n               | *\n               | * @param a integer parameter\n               | */\n               |fun test(a: Int): Unit = Unit\n            \"\"\".trimMargin(),\n            DiktatError(3, 4, ruleId, \"${KDOC_NEWLINES_BEFORE_BASIC_TAGS.warnText()} @param\", true)\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.KDOC_NEWLINES_BEFORE_BASIC_TAGS)\n    fun `basic tags block should have empty line before if there is other KDoc content`() {\n        lintMethod(\n            \"\"\"/**\n               | * Lorem ipsum\n               | * dolor sit amet\n               | * @param a integer parameter\n               | */\n               |fun test(a: Int): Unit = Unit\n            \"\"\".trimMargin(),\n            DiktatError(4, 4, ruleId, \"${KDOC_NEWLINES_BEFORE_BASIC_TAGS.warnText()} @param\", true)\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.KDOC_NO_NEWLINE_AFTER_SPECIAL_TAGS)\n    fun `special tags should have exactly one newline after them (positive example)`() {\n        val validCode = \"\"\"\n            /**\n             * @implSpec stuff\n             * implementation details\n             *\n             * @apiNote foo\n             *\n             * @implNote bar\n             *\n             */\n            $funCode\n        \"\"\".trimIndent()\n\n        lintMethod(validCode)\n    }\n\n    @Test\n    @Tag(WarningNames.KDOC_NO_NEWLINE_AFTER_SPECIAL_TAGS)\n    fun `special tags should have exactly one newline after them (no newline)`() {\n        val invalidCode = \"\"\"\n            /**\n             * @implSpec stuff\n             * @apiNote foo\n             * @implNote bar\n             */\n            $funCode\n        \"\"\".trimIndent()\n\n        lintMethod(invalidCode,\n            DiktatError(2, 16, ruleId,\n                \"${KDOC_NO_NEWLINE_AFTER_SPECIAL_TAGS.warnText()} @implSpec, @apiNote, @implNote\", true))\n    }\n\n    @Test\n    @Tag(WarningNames.KDOC_NO_NEWLINE_AFTER_SPECIAL_TAGS)\n    fun `special tags should have exactly one newline after them (many lines)`() {\n        val invalidCode = \"\"\"\n            /**\n             * @implSpec stuff\n             *\n\n             * @apiNote foo\n             *\n             *\n             *\n             * @implNote bar\n\n             */\n            $funCode\n        \"\"\".trimIndent()\n\n        lintMethod(invalidCode,\n            DiktatError(2, 16, ruleId,\n                \"${KDOC_NO_NEWLINE_AFTER_SPECIAL_TAGS.warnText()} @implSpec, @apiNote, @implNote\", true))\n    }\n\n    @Test\n    @Tag(WarningNames.KDOC_CONTAINS_DATE_OR_AUTHOR)\n    fun `@author tag is not allowed in header comment`() {\n        lintMethod(\n            \"\"\"\n                |/**\n                | * Description of this file\n                | * @author anonymous\n                | */\n                |\n                |package com.saveourtool.diktat.example\n                |\n                |/**\n                | * Description of this class\n                | * @author anonymous\n                | */\n                |class Example { }\n            \"\"\".trimMargin(),\n            DiktatError(3, 4, ruleId, \"${Warnings.KDOC_CONTAINS_DATE_OR_AUTHOR.warnText()} @author anonymous\"),\n            DiktatError(10, 4, ruleId, \"${Warnings.KDOC_CONTAINS_DATE_OR_AUTHOR.warnText()} @author anonymous\"),\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.KDOC_CONTAINS_DATE_OR_AUTHOR)\n    fun `@since tag should only contain versions`() {\n        lintMethod(\n            \"\"\"\n                |/**\n                | * Description of this file\n                | * @since 2019-10-11\n                | * @since 19-10-11\n                | * @since 2019.10.11\n                | * @since 2019/10/11\n                | * @since 11 Oct 2019\n                | * @since 1.2.3\n                | * @since 1.2.3-1\n                | * @since 1.2.3-SNAPSHOT\n                | * @since 1.2.3-rc-1\n                | * @since 1.2.3.RELEASE\n                | */\n                |\n                |package com.saveourtool.diktat.example\n                |\n                |/**\n                | * Description of this file\n                | * @since 2019-10-11\n                | * @since 1.2.3\n                | */\n                |class Example { }\n            \"\"\".trimMargin(),\n            DiktatError(3, 4, ruleId, \"${Warnings.KDOC_CONTAINS_DATE_OR_AUTHOR.warnText()} @since 2019-10-11\"),\n            DiktatError(4, 4, ruleId, \"${Warnings.KDOC_CONTAINS_DATE_OR_AUTHOR.warnText()} @since 19-10-11\"),\n            DiktatError(5, 4, ruleId, \"${Warnings.KDOC_CONTAINS_DATE_OR_AUTHOR.warnText()} @since 2019.10.11\"),\n            DiktatError(6, 4, ruleId, \"${Warnings.KDOC_CONTAINS_DATE_OR_AUTHOR.warnText()} @since 2019/10/11\"),\n            DiktatError(7, 4, ruleId, \"${Warnings.KDOC_CONTAINS_DATE_OR_AUTHOR.warnText()} @since 11 Oct 2019\"),\n            DiktatError(19, 4, ruleId, \"${Warnings.KDOC_CONTAINS_DATE_OR_AUTHOR.warnText()} @since 2019-10-11\"),\n            rulesConfigList = emptyList()\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.KDOC_CONTAINS_DATE_OR_AUTHOR)\n    fun `@since tag should only contain versions - with configured regex`() {\n        lintMethod(\n            \"\"\"\n                |/**\n                | * Description of this file\n                | * @since 2019-10-11\n                | * @since 1.2.3-rc-1\n                | * @since 1.2.3.RELEASE\n                | */\n                |\n                |package com.saveourtool.diktat.example\n                |\n                |/**\n                | * Description of this file\n                | * @since 2019-10-11\n                | * @since 1.2.3\n                | */\n                |class Example { }\n            \"\"\".trimMargin(),\n            DiktatError(3, 4, ruleId, \"${Warnings.KDOC_CONTAINS_DATE_OR_AUTHOR.warnText()} @since 2019-10-11\"),\n            DiktatError(5, 4, ruleId, \"${Warnings.KDOC_CONTAINS_DATE_OR_AUTHOR.warnText()} @since 1.2.3.RELEASE\"),\n            DiktatError(12, 4, ruleId, \"${Warnings.KDOC_CONTAINS_DATE_OR_AUTHOR.warnText()} @since 2019-10-11\"),\n            rulesConfigList = listOf(\n                RulesConfig(\n                    Warnings.KDOC_CONTAINS_DATE_OR_AUTHOR.name, true, mapOf(\n                        \"versionRegex\" to \"\\\\d+\\\\.\\\\d+\\\\.\\\\d+[-\\\\w\\\\d]*\"\n                    )\n                )\n            )\n        )\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/test/kotlin/com/saveourtool/diktat/ruleset/chapter2/KdocMethodsFixTest.kt",
    "content": "package com.saveourtool.diktat.ruleset.chapter2\n\nimport com.saveourtool.diktat.ruleset.rules.chapter2.kdoc.KdocMethods\nimport com.saveourtool.diktat.util.FixTestBase\n\nimport generated.WarningNames\nimport org.junit.jupiter.api.Tag\nimport org.junit.jupiter.api.Tags\nimport org.junit.jupiter.api.Test\n\nclass KdocMethodsFixTest : FixTestBase(\"test/paragraph2/kdoc/package/src/main/kotlin/com/saveourtool/diktat/kdoc/methods\",\n    ::KdocMethods) {\n    @Test\n    @Tag(WarningNames.MISSING_KDOC_TOP_LEVEL)\n    fun `Rule should suggest KDoc template for missing KDocs`() {\n        fixAndCompare(\"MissingKdocExpected.kt\", \"MissingKdocTested.kt\")\n    }\n\n    @Test\n    @Tag(WarningNames.MISSING_KDOC_ON_FUNCTION)\n    fun `KDoc template should be placed before modifiers`() {\n        fixAndCompare(\"MissingKdocWithModifiersExpected.kt\", \"MissingKdocWithModifiersTest.kt\")\n    }\n\n    @Test\n    @Tag(WarningNames.MISSING_KDOC_ON_FUNCTION)\n    fun `KDoc should be for function with single line body`() {\n        fixAndCompare(\"MissingKdocOnFunctionExpected.kt\", \"MissingKdocOnFunctionTest.kt\")\n    }\n\n    @Test\n    @Tag(WarningNames.KDOC_EMPTY_KDOC)\n    fun `Rule should not suggest empty KDoc templates`() {\n        fixAndCompare(\"EmptyKdocExpected.kt\", \"EmptyKdocTested.kt\")\n    }\n\n    @Test\n    @Tag(WarningNames.KDOC_WITHOUT_PARAM_TAG)\n    fun `@param tag should be added to existing KDoc`() {\n        fixAndCompare(\"ParamTagInsertionExpected.kt\", \"ParamTagInsertionTested.kt\")\n    }\n\n    @Test\n    @Tag(WarningNames.KDOC_WITHOUT_RETURN_TAG)\n    fun `@return tag should be added to existing KDoc`() {\n        fixAndCompare(\"ReturnTagInsertionExpected.kt\", \"ReturnTagInsertionTested.kt\")\n    }\n\n    @Test\n    @Tag(WarningNames.KDOC_WITHOUT_THROWS_TAG)\n    fun `@throws tag should be added to existing KDoc`() {\n        fixAndCompare(\"ThrowsTagInsertionExpected.kt\", \"ThrowsTagInsertionTested.kt\")\n    }\n\n    @Test\n    @Tags(\n        Tag(WarningNames.KDOC_WITHOUT_PARAM_TAG),\n        Tag(WarningNames.KDOC_WITHOUT_RETURN_TAG),\n        Tag(WarningNames.KDOC_WITHOUT_THROWS_TAG)\n    )\n    fun `KdocMethods rule should reformat code (full example)`() {\n        fixAndCompare(\"KdocMethodsFullExpected.kt\", \"KdocMethodsFullTested.kt\")\n    }\n\n    @Test\n    @Tag(WarningNames.KDOC_WITHOUT_THROWS_TAG)\n    fun `Should add throws tag only for throw without catch`() {\n        fixAndCompare(\"KdocWithoutThrowsTagExpected.kt\", \"KdocWithoutThrowsTagTested.kt\")\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/test/kotlin/com/saveourtool/diktat/ruleset/chapter2/KdocMethodsTest.kt",
    "content": "package com.saveourtool.diktat.ruleset.chapter2\n\nimport com.saveourtool.diktat.common.config.rules.DIKTAT_COMMON\nimport com.saveourtool.diktat.common.config.rules.DIKTAT_RULE_SET_ID\nimport com.saveourtool.diktat.common.config.rules.RulesConfig\nimport com.saveourtool.diktat.ruleset.constants.Warnings.KDOC_TRIVIAL_KDOC_ON_FUNCTION\nimport com.saveourtool.diktat.ruleset.constants.Warnings.KDOC_WITHOUT_PARAM_TAG\nimport com.saveourtool.diktat.ruleset.constants.Warnings.KDOC_WITHOUT_RETURN_TAG\nimport com.saveourtool.diktat.ruleset.constants.Warnings.KDOC_WITHOUT_THROWS_TAG\nimport com.saveourtool.diktat.ruleset.constants.Warnings.MISSING_KDOC_ON_FUNCTION\nimport com.saveourtool.diktat.ruleset.rules.chapter2.kdoc.KdocMethods\nimport com.saveourtool.diktat.util.LintTestBase\n\nimport com.saveourtool.diktat.api.DiktatError\nimport generated.WarningNames\nimport org.junit.jupiter.api.Tag\nimport org.junit.jupiter.api.Tags\nimport org.junit.jupiter.api.Test\nimport org.junit.jupiter.api.io.TempDir\nimport java.nio.file.Path\n\nclass KdocMethodsTest : LintTestBase(::KdocMethods) {\n    private val ruleId: String = \"$DIKTAT_RULE_SET_ID:${KdocMethods.NAME_ID}\"\n    private val funCode = \"\"\"\n        fun doubleInt(a: Int): Int {\n            if (Config.condition) throw IllegalStateException()\n            return 2 * a\n        }\n    \"\"\".trimIndent()\n\n    @Test\n    @Tags(\n        Tag(WarningNames.KDOC_WITHOUT_PARAM_TAG),\n        Tag(WarningNames.KDOC_WITHOUT_RETURN_TAG),\n        Tag(WarningNames.KDOC_WITHOUT_THROWS_TAG)\n    )\n    fun `Accessible methods with parameters, return type and throws should have proper KDoc (positive example)`() {\n        val validCode = \"\"\"\n            /**\n             * Test method\n             * @param a - dummy integer\n             * @return doubled value\n             * @throws IllegalStateException\n             */\n            $funCode\n        \"\"\".trimIndent()\n\n        lintMethod(validCode)\n    }\n\n    @Test\n    @Tag(WarningNames.MISSING_KDOC_TOP_LEVEL)\n    fun `Warning should not be triggered for private functions`() {\n        val validCode = \"private $funCode\"\n\n        lintMethod(validCode)\n    }\n\n    @Test\n    @Tag(WarningNames.MISSING_KDOC_TOP_LEVEL)\n    fun `anonymous function`() {\n        val code = \"\"\"\n            package com.saveourtool.diktat.test\n\n            fun foo() {\n                val sum: (Int) -> Int = fun(x): Int = x + x\n            }\n\n        \"\"\".trimIndent()\n        lintMethod(code,\n            DiktatError(3, 1, ruleId, \"${MISSING_KDOC_ON_FUNCTION.warnText()} foo\", false),\n        )\n    }\n\n    @Test\n    @Tags(\n        Tag(WarningNames.KDOC_WITHOUT_PARAM_TAG),\n        Tag(WarningNames.KDOC_WITHOUT_RETURN_TAG),\n        Tag(WarningNames.KDOC_WITHOUT_THROWS_TAG),\n        Tag(WarningNames.MISSING_KDOC_ON_FUNCTION)\n    )\n    fun `Warning should not be triggered for functions in tests`(@TempDir tempDir: Path) {\n        val validCode = \"@Test $funCode\"\n        val complexAnnotationCode = \"@Anno(test = [\\\"args\\\"]) $funCode\"\n\n        // do not force KDoc on annotated function\n        lintMethodWithFile(validCode, tempDir = tempDir, fileName = \"src/main/kotlin/com/saveourtool/diktat/Example.kt\")\n        // no false positive triggers on annotations\n        lintMethodWithFile(complexAnnotationCode,\n            tempDir = tempDir,\n            fileName = \"src/main/kotlin/com/saveourtool/diktat/Example.kt\",\n            DiktatError(1, 1, ruleId, \"${MISSING_KDOC_ON_FUNCTION.warnText()} doubleInt\", true)\n        )\n        // should check all .kt files unless both conditions on location and name are true\n        lintMethodWithFile(funCode,\n            tempDir = tempDir,\n            fileName = \"src/test/kotlin/com/saveourtool/diktat/Example.kt\",\n            DiktatError(1, 1, ruleId, \"${MISSING_KDOC_ON_FUNCTION.warnText()} doubleInt\", true)\n        )\n        // should allow to set custom test dirs\n        lintMethodWithFile(funCode,\n            tempDir = tempDir,\n            fileName = \"src/jvmTest/kotlin/com/saveourtool/diktat/ExampleTest.kt\",\n            rulesConfigList = listOf(RulesConfig(DIKTAT_COMMON, true, mapOf(\"testDirs\" to \"test,jvmTest\")))\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.KDOC_WITHOUT_PARAM_TAG)\n    fun `Empty parameter list should not trigger warning about @param`() {\n        val validCode = \"\"\"\n            /**\n             * Test method\n             * @return zero\n             * @throws IllegalStateException\n             */\n            fun foo(): Int {\n                return 0\n            }\n        \"\"\".trimIndent()\n\n        lintMethod(validCode)\n    }\n\n    @Test\n    @Tag(WarningNames.KDOC_WITHOUT_PARAM_TAG)\n    fun `All methods with parameters should have @param KDoc`() {\n        val invalidKdoc = \"\"\"\n            /**\n             * Test method\n             * @return doubled value\n             * @throws IllegalStateException\n             */\n        \"\"\".trimIndent()\n        val invalidCode = \"\"\"\n            $invalidKdoc\n            $funCode\n        \"\"\".trimIndent()\n\n        lintMethod(invalidCode,\n            DiktatError(1, 13, ruleId, \"${KDOC_WITHOUT_PARAM_TAG.warnText()} doubleInt (a)\", true)\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.KDOC_WITHOUT_PARAM_TAG)\n    fun `All methods with parameters should have @param KDoc for each parameter`() {\n        val invalidKdoc = \"\"\"\n            /**\n             * Test method\n             * @param a - dummy integer\n             * @return doubled value\n             * @throws IllegalStateException\n             */\n        \"\"\".trimIndent()\n        val invalidCode = \"\"\"\n            $invalidKdoc\n            fun addInts(a: Int, b: Int): Int = a + b\n        \"\"\".trimIndent()\n\n        lintMethod(invalidCode,\n            DiktatError(1, 12, ruleId, \"${KDOC_WITHOUT_PARAM_TAG.warnText()} addInts (b)\", true)\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.KDOC_WITHOUT_RETURN_TAG)\n    fun `All methods with explicit return type excluding Unit should have @return KDoc`() {\n        val invalidKdoc = \"\"\"\n            /**\n             * Test method\n             * @param a - dummy integer\n             * @throws IllegalStateException\n             */\n        \"\"\".trimIndent()\n        val invalidCode = \"\"\"\n            $invalidKdoc\n            $funCode\n        \"\"\".trimIndent()\n\n        lintMethod(invalidCode,\n            DiktatError(1, 13, ruleId, \"${KDOC_WITHOUT_RETURN_TAG.warnText()} doubleInt\", true)\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.KDOC_WITHOUT_RETURN_TAG)\n    fun `All methods with expression body should have @return tag or explicitly set return type to Unit`() {\n        val kdocWithoutReturn = \"\"\"\n            /**\n             * Test method\n             * @param a - dummy integer\n             * @throws IllegalStateException\n             */\n        \"\"\".trimIndent()\n\n        val invalidCode = \"\"\"\n            $kdocWithoutReturn\n            fun foo(a: Int) = bar(2 * a)\n\n            $kdocWithoutReturn\n            fun bar(a: Int): Unit = this.list.add(a)\n\n            private val list = mutableListOf<Int>()\n        \"\"\".trimIndent()\n\n        lintMethod(invalidCode,\n            DiktatError(1, 12, ruleId, \"${KDOC_WITHOUT_RETURN_TAG.warnText()} foo\", true)\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.KDOC_WITHOUT_THROWS_TAG)\n    fun `All methods with throw in method body should have @throws KDoc`() {\n        val invalidKdoc = \"\"\"\n            /**\n             * Test method\n             * @param a - dummy integer\n             * @return doubled value\n             */\n        \"\"\".trimIndent()\n        val invalidCode = \"\"\"\n            $invalidKdoc\n            $funCode\n        \"\"\".trimIndent()\n\n        lintMethod(invalidCode,\n            DiktatError(1, 13, ruleId, \"${KDOC_WITHOUT_THROWS_TAG.warnText()} doubleInt (IllegalStateException)\", true)\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.KDOC_WITHOUT_THROWS_TAG)\n    fun `Linter shouldn't detect throws inside comments`() {\n        val invalidKdoc = \"\"\"\n            /**\n             * Test method\n             * @param a - dummy integer\n             * @return doubled value\n             */\n        \"\"\".trimIndent()\n        val invalidCode = \"\"\"\n            $invalidKdoc\n            fun foo(a: Int) {\n                // throw Exception()\n                return bar\n            }\n        \"\"\".trimIndent()\n\n        lintMethod(invalidCode)\n    }\n\n    @Test\n    @Tag(WarningNames.KDOC_WITHOUT_THROWS_TAG)\n    fun `All thrown exceptions should be in KDoc`() {\n        val invalidCode = \"\"\"\n            /**\n             * Test method\n             * @param a - dummy integer\n             * @return doubled value\n             * @throws IllegalStateException\n             */\n            fun doubleInt(a: Int): Int {\n                if (Config.condition) throw IllegalStateException()\n                if (Config.condition2) throw IllegalAccessException()\n                return 2 * a\n            }\n        \"\"\".trimIndent()\n\n        lintMethod(invalidCode,\n            DiktatError(1, 1, ruleId, \"${KDOC_WITHOUT_THROWS_TAG.warnText()} doubleInt (IllegalAccessException)\", true)\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.KDOC_WITHOUT_THROWS_TAG)\n    fun `No warning when throw has matching catch`() {\n        lintMethod(\n            \"\"\"\n                    /**\n                      * Test method\n                      * @param a: Int - dummy integer\n                      * @return doubled value\n                      */\n                    fun foo(a: Int): Int {\n                        try {\n                            if (a < 0)\n                                throw NumberFormatExecption()\n                        } catch (e: ArrayIndexOutOfBounds) {\n                            print(1)\n                        } catch (e: NullPointerException) {\n                            print(2)\n                        } catch (e: NumberFormatExecption) {\n                            print(3)\n                        }\n                        return 2 * a\n                    }\n            \"\"\".trimIndent())\n    }\n\n    @Test\n    @Tag(WarningNames.KDOC_WITHOUT_THROWS_TAG)\n    fun `Warning when throw doesn't have matching catch`() {\n        lintMethod(\n            \"\"\"\n                    /**\n                      * Test method\n                      * @param a: Int - dummy integer\n                      * @return doubled value\n                      */\n                    fun foo(a: Int): Int {\n                        try {\n                            if (a < 0)\n                                throw NumberFormatException()\n                        throw NullPointerException()\n                        throw NoSuchElementException()\n                        } catch (e: NoSuchElementException) {\n                            print(1)\n                        } catch (e: IllegalArgumentException) {\n                            print(2)\n                        }\n                        return 2 * a\n                    }\n            \"\"\".trimIndent(),\n        DiktatError(1, 1, ruleId, \"${KDOC_WITHOUT_THROWS_TAG.warnText()} foo (NullPointerException)\", true))\n    }\n\n    @Test\n    @Tag(WarningNames.KDOC_WITHOUT_THROWS_TAG)\n    fun `No warning when throw has matching catch, which is parent exception to throw`() {\n        lintMethod(\n            \"\"\"\n                    /**\n                      * Test method\n                      * @param a: Int - dummy integer\n                      * @return doubled value\n                      */\n                    fun foo(a: Int): Int {\n                        try {\n                            if (a < 0)\n                                throw NumberFormatException()\n                        } catch (e: IllegalArgumentException) {\n                            print(1)\n                        }\n                        return 2 * a\n                    }\n            \"\"\".trimIndent())\n    }\n\n    @Test\n    @Tag(WarningNames.MISSING_KDOC_TOP_LEVEL)\n    fun `do not force documentation on standard methods`() {\n        lintMethod(\n            \"\"\"\n                    |class Example {\n                    |    override fun toString() = \"example\"\n                    |\n                    |    override fun equals(other: Any?) = false\n                    |\n                    |    override fun hashCode() = 42\n                    |}\n                    |\n                    |fun main() { }\n            \"\"\".trimMargin()\n        )\n\n        lintMethod(\n            \"\"\"\n                    |class Example {\n                    |    override fun toString(): String { return \"example\" }\n                    |\n                    |    override fun equals(other: Any?): Boolean { return false }\n                    |\n                    |    override fun hashCode(): Int { return 42 }\n                    |}\n                    |\n                    |fun main(vararg args: String) { }\n            \"\"\".trimMargin()\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.MISSING_KDOC_ON_FUNCTION)\n    fun `should not force documentation on single line getters and setters`() {\n        lintMethod(\n            \"\"\"\n                    |class Example {\n                    |    fun setX(x: Type) {\n                    |        this.x = x\n                    |    }\n                    |\n                    |    fun getX(): Type {\n                    |        return x\n                    |    }\n                    |\n                    |    fun getY() = this.y\n                    |\n                    |    fun setY(y: Type) {\n                    |        this.validate(y)\n                    |        this.y = y\n                    |    }\n                    |\n                    |    fun getZ(): TypeZ {\n                    |        baz(z)\n                    |        return z\n                    |    }\n                    |}\n            \"\"\".trimMargin(),\n            DiktatError(12, 5, ruleId, \"${MISSING_KDOC_ON_FUNCTION.warnText()} setY\", true),\n            DiktatError(17, 5, ruleId, \"${MISSING_KDOC_ON_FUNCTION.warnText()} getZ\", true)\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.MISSING_KDOC_ON_FUNCTION)\n    fun `regression - warn about missing KDoc even if it cannot be autocorrected`() {\n        lintMethod(\n            \"\"\"\n                    |fun foo() { }\n            \"\"\".trimMargin(),\n            DiktatError(1, 1, ruleId, \"${MISSING_KDOC_ON_FUNCTION.warnText()} foo\", false)\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.KDOC_TRIVIAL_KDOC_ON_FUNCTION)\n    fun `should check if KDoc is not trivial`() {\n        lintMethod(\n            \"\"\"\n                    |/**\n                    | * Returns X\n                    | */\n                    |fun getX(): TypeX { return x }\n            \"\"\".trimMargin(),\n            DiktatError(2, 3, ruleId, \"${KDOC_TRIVIAL_KDOC_ON_FUNCTION.warnText()} Returns X\", false)\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.MISSING_KDOC_ON_FUNCTION)\n    fun `should not trigger on override funcs`() {\n        lintMethod(\n            \"\"\"\n                    |class Some : A {\n                    |   override fun foo() {}\n                    |\n                    |   override fun bar(t: T): U { return U() }\n                    |}\n            \"\"\".trimMargin()\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.MISSING_KDOC_ON_FUNCTION)\n    fun `should check if KfDoc is not trivial`() {\n        lintMethod(\n            \"\"\"\n                    |fun foo(x: Int): TypeX {\n                    |   val q = goo()\n                    |   throw UnsupportedOperationException()\n                    |   return qwe\n                    |}\n            \"\"\".trimMargin(),\n            DiktatError(1, 1, ruleId, \"${MISSING_KDOC_ON_FUNCTION.warnText()} foo\", true)\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.MISSING_KDOC_ON_FUNCTION)\n    fun `KDoc should be for function with single line body`() {\n        lintMethod(\n            \"\"\"\n                    |fun hasNoChildren() = children.size == 0\n                    |fun getFirstChild() = children.elementAtOrNull(0)\n            \"\"\".trimMargin(),\n            DiktatError(1, 1, ruleId, \"${MISSING_KDOC_ON_FUNCTION.warnText()} hasNoChildren\", true),\n            DiktatError(2, 1, ruleId, \"${MISSING_KDOC_ON_FUNCTION.warnText()} getFirstChild\", true)\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.MISSING_KDOC_ON_FUNCTION)\n    fun `KDoc shouldn't be for function with name as method`() {\n        lintMethod(\n            \"\"\"\n                    |@GetMapping(\"/projects\")\n                    |fun getProjects() = projectService.getProjects(x.prop())\n            \"\"\".trimMargin(),\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.MISSING_KDOC_ON_FUNCTION)\n    fun `KDoc shouldn't trigger on actual methods`() {\n        lintMethod(\n            \"\"\"\n                    |actual fun writeToConsoleAc(msg: String, outputType: OutputStreamType) {}\n                    |expect fun writeToConsoleEx(msg: String, outputType: OutputStreamType) {}\n            \"\"\".trimMargin(),\n            DiktatError(2, 1, ruleId, \"${MISSING_KDOC_ON_FUNCTION.warnText()} writeToConsoleEx\", true),\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.MISSING_KDOC_ON_FUNCTION)\n    fun `KDoc shouldn't trigger on local functions`() {\n        lintMethod(\n            \"\"\"\n                |fun printHelloAndBye() {\n                |    fun printHello() {\n                |        print(\"Hello\")\n                |    }\n                |    printHello()\n                |    val ab = 5\n                |    ab?.let {\n                |        fun printBye() {\n                |            print(\"Bye\")\n                |        }\n                |        printBye()\n                |    }\n                |}\n            \"\"\".trimMargin(),\n            DiktatError(1, 1, ruleId, \"${MISSING_KDOC_ON_FUNCTION.warnText()} printHelloAndBye\", false),\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.MISSING_KDOC_ON_FUNCTION)\n    fun `KDoc shouldn't trigger on functions with KDoc`() {\n        lintMethod(\n            \"\"\"\n                |/**\n                | * prints \"Hello\" and \"Bye\"\n                | */\n                |fun printHelloAndBye() {\n                |    fun printHello() {\n                |        print(\"Hello\")\n                |    }\n                |    printHello()\n                |    val ab = 5\n                |    ab?.let {\n                |        fun printBye() {\n                |            print(\"Bye\")\n                |        }\n                |        printBye()\n                |    }\n                |}\n            \"\"\".trimMargin(),\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.MISSING_KDOC_ON_FUNCTION)\n    fun `KDoc shouldn't trigger on nested local functions`() {\n        lintMethod(\n            \"\"\"\n                |fun printHelloAndBye() {\n                |    fun printHello() {\n                |        print(\"Hello\")\n                |        fun printBye() {\n                |            print(\"Bye\")\n                |        }\n                |        fun printDots() {\n                |            print(\"...\")\n                |        }\n                |        printBye()\n                |        printDots()\n                |    }\n                |    printHello()\n                |}\n            \"\"\".trimMargin(),\n            DiktatError(1, 1, ruleId, \"${MISSING_KDOC_ON_FUNCTION.warnText()} printHelloAndBye\", false),\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.MISSING_KDOC_ON_FUNCTION)\n    fun `KDoc shouldn't trigger on local functions with KDoc`() {\n        lintMethod(\n            \"\"\"\n                |fun printHelloAndBye() {\n                |    fun printHello() {\n                |        print(\"Hello\")\n                |    }\n                |    printHello()\n                |    val ab = 5\n                |    ab?.let {\n                |        /**\n                |         * prints \"Bye\"\n                |         */\n                |        fun printBye() {\n                |            print(\"Bye\")\n                |        }\n                |        printBye()\n                |    }\n                |}\n            \"\"\".trimMargin(),\n            DiktatError(1, 1, ruleId, \"${MISSING_KDOC_ON_FUNCTION.warnText()} printHelloAndBye\", false),\n        )\n    }\n\n}\n"
  },
  {
    "path": "diktat-rules/src/test/kotlin/com/saveourtool/diktat/ruleset/chapter2/KdocParamPresentWarnTest.kt",
    "content": "package com.saveourtool.diktat.ruleset.chapter2\n\nimport com.saveourtool.diktat.common.config.rules.DIKTAT_RULE_SET_ID\nimport com.saveourtool.diktat.ruleset.constants.Warnings.KDOC_WITHOUT_PARAM_TAG\nimport com.saveourtool.diktat.ruleset.constants.Warnings.MISSING_KDOC_ON_FUNCTION\nimport com.saveourtool.diktat.ruleset.rules.chapter2.kdoc.KdocMethods\nimport com.saveourtool.diktat.util.LintTestBase\n\nimport com.saveourtool.diktat.api.DiktatError\nimport generated.WarningNames\nimport org.junit.jupiter.api.Tag\nimport org.junit.jupiter.api.Tags\nimport org.junit.jupiter.api.Test\n\nclass KdocParamPresentWarnTest : LintTestBase(::KdocMethods) {\n    private val ruleId = \"$DIKTAT_RULE_SET_ID:${KdocMethods.NAME_ID}\"\n\n    @Test\n    @Tag(WarningNames.KDOC_WITHOUT_PARAM_TAG)\n    fun `check simple correct example`() {\n        lintMethod(\n            \"\"\"\n                    |/**\n                    |* @param a - leftOffset\n                    |*/\n                    |fun foo(a: Int) {}\n            \"\"\".trimMargin()\n        )\n    }\n\n    @Test\n    @Tags(Tag(WarningNames.KDOC_WITHOUT_PARAM_TAG), Tag(WarningNames.KDOC_WITHOUT_PARAM_TAG))\n    fun `check wrong example with russian letter name`() {\n        lintMethod(\n            \"\"\"\n                    |/**\n                    |* @param A - leftOffset\n                    |* @param В - russian letter\n                    |*/\n                    |fun foo(a: Int, B: Int) {}\n            \"\"\".trimMargin(),\n            DiktatError(1, 1, ruleId, \"${KDOC_WITHOUT_PARAM_TAG.warnText()} foo (a, B)\", true),\n            DiktatError(2, 3, ruleId, \"${KDOC_WITHOUT_PARAM_TAG.warnText()} A param isn't present in argument list\"),\n            DiktatError(3, 3, ruleId, \"${KDOC_WITHOUT_PARAM_TAG.warnText()} В param isn't present in argument list\")\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.KDOC_WITHOUT_PARAM_TAG)\n    fun `check wrong example without param in fun`() {\n        lintMethod(\n            \"\"\"\n                    |/**\n                    |* @param A - leftOffset\n                    |*/\n                    |fun foo() {}\n            \"\"\".trimMargin(),\n            DiktatError(2, 3, ruleId, \"${KDOC_WITHOUT_PARAM_TAG.warnText()} A param isn't present in argument list\")\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.KDOC_WITHOUT_PARAM_TAG)\n    fun `check empty param`() {\n        lintMethod(\n            \"\"\"\n                    |/**\n                    |* @param\n                    |*/\n                    |fun foo() {}\n                    |\n                    |/**\n                    |* @param\n                    |*/\n                    |fun foo (a: Int) {}\n            \"\"\".trimMargin(),\n            DiktatError(6, 1, ruleId, \"${KDOC_WITHOUT_PARAM_TAG.warnText()} foo (a)\", true)\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.KDOC_WITHOUT_PARAM_TAG)\n    fun `check different order`() {\n        lintMethod(\n            \"\"\"\n                    |/**\n                    |* @param a - qwe\n                    |* @param b - qwe\n                    |*/\n                    |fun foo(b: Int, a: Int) {}\n            \"\"\".trimMargin()\n        )\n    }\n\n    @Test\n    @Tags(Tag(WarningNames.KDOC_WITHOUT_PARAM_TAG), Tag(WarningNames.MISSING_KDOC_ON_FUNCTION))\n    fun `check without kdoc and fun `() {\n        lintMethod(\n            \"\"\"\n                    |fun foo(b: Int, a: Int) {}\n                    |\n                    |/**\n                    |* @param a - qwe\n                    |*/\n            \"\"\".trimMargin(),\n            DiktatError(1, 1, ruleId, \"${MISSING_KDOC_ON_FUNCTION.warnText()} foo\", true)\n        )\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/test/kotlin/com/saveourtool/diktat/ruleset/chapter2/comments/CommentedCodeTest.kt",
    "content": "package com.saveourtool.diktat.ruleset.chapter2.comments\n\nimport com.saveourtool.diktat.common.config.rules.DIKTAT_RULE_SET_ID\nimport com.saveourtool.diktat.ruleset.constants.Warnings.COMMENTED_OUT_CODE\nimport com.saveourtool.diktat.ruleset.rules.chapter2.comments.CommentsRule\nimport com.saveourtool.diktat.util.LintTestBase\n\nimport com.saveourtool.diktat.api.DiktatError\nimport generated.WarningNames\nimport org.junit.jupiter.api.Tag\nimport org.junit.jupiter.api.Test\n\nclass CommentedCodeTest : LintTestBase(::CommentsRule) {\n    private val ruleId = \"$DIKTAT_RULE_SET_ID:${CommentsRule.NAME_ID}\"\n\n    @Test\n    @Tag(WarningNames.COMMENTED_OUT_CODE)\n    fun `Should warn if commented out import or package directive is detected (single line comments)`() {\n        lintMethod(\n            \"\"\"\n                |//package com.saveourtool.diktat.example\n                |\n                |import org.junit.Test\n                |// this is an actual comment\n                |//import org.junit.Ignore\n            \"\"\".trimMargin(),\n            DiktatError(1, 1, ruleId, \"${COMMENTED_OUT_CODE.warnText()} package com.saveourtool.diktat.example\", false),\n            DiktatError(5, 1, ruleId, \"${COMMENTED_OUT_CODE.warnText()} import org.junit.Ignore\", false)\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.COMMENTED_OUT_CODE)\n    fun `Should warn if commented out imports are detected (block comments)`() {\n        lintMethod(\n            \"\"\"\n               |/*import org.junit.Test\n               |import org.junit.Ignore*/\n            \"\"\".trimMargin(),\n            DiktatError(1, 1, ruleId, \"${COMMENTED_OUT_CODE.warnText()} import org.junit.Test\", false),\n            DiktatError(1, 1, ruleId, \"${COMMENTED_OUT_CODE.warnText()} import org.junit.Ignore\", false)\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.COMMENTED_OUT_CODE)\n    fun `Should warn if commented out code is detected (block comments)`() {\n        lintMethod(\n            \"\"\"\n               |import org.junit.Test\n               |\n               |fun foo(a: Int): Int {\n               |    /* println(a + 42)\n               |    println(\"This is a test string\")\n               |    val b = a*10\n               |    */\n               |    return 0\n               |}\n            \"\"\".trimMargin(),\n            DiktatError(4, 5, ruleId, \"${COMMENTED_OUT_CODE.warnText()} println(a + 42)\", false)\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.COMMENTED_OUT_CODE)\n    fun `Should warn if commented out code is detected (single line comments)`() {\n        lintMethod(\n            \"\"\"\n               |import org.junit.Test\n               |\n               |fun foo(a: Int): Int {\n               |//    println(a + 42)\n               |//    println(\"This is a test string\")\n               |    return 0\n               |}\n            \"\"\".trimMargin())\n    }\n\n    @Test\n    @Tag(WarningNames.COMMENTED_OUT_CODE)\n    fun `Should warn if commented out function is detected single line comments`() {\n        lintMethod(\n            \"\"\"\n               |import org.junit.Test\n               |\n               |//fun foo(a: Int): Int {\n               |//    println(a + 42)\n               |//    println(\"This is a test string\")\n               |//    return 0\n               |//}\n            \"\"\".trimMargin(),\n            DiktatError(3, 1, ruleId, \"${COMMENTED_OUT_CODE.warnText()} fun foo(a: Int): Int {\", false)\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.COMMENTED_OUT_CODE)\n    fun `Should warn if commented out function is detected - single line comments with surrounding text`() {\n        lintMethod(\n            \"\"\"\n               |import org.junit.Test\n               |\n               |// this function is disabled for now\n               |//fun foo(a: Int): Int {\n               |//    println(a + 42)\n               |//    println(\"This is a test string\")\n               |//    return 0\n               |//}\n            \"\"\".trimMargin(),\n            DiktatError(4, 1, ruleId, \"${COMMENTED_OUT_CODE.warnText()} fun foo(a: Int): Int {\", false)\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.COMMENTED_OUT_CODE)\n    fun `Should warn if commented out function is detected (block comment)`() {\n        lintMethod(\n            \"\"\"\n               |import org.junit.Test\n               |\n               |/*fun foo(a: Int): Int {\n               |    println(a + 42)\n               |    println(\"This is a test string\")\n               |    return 0\n               |}*/\n            \"\"\".trimMargin(),\n            DiktatError(3, 1, ruleId, \"${COMMENTED_OUT_CODE.warnText()} fun foo(a: Int): Int {\", false)\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.COMMENTED_OUT_CODE)\n    fun `Should warn if detects commented out code (example with indents)`() {\n        lintMethod(\n            \"\"\"\n                |//import org.junit.Ignore\n                |import org.junit.Test\n                |\n                |class Example {\n                |    // this function is disabled for now\n                |    //fun foo(a: Int): Int {\n                |    //    println(a + 42)\n                |    //    println(\"This is a test string\")\n                |    //    return 0\n                |    //}\n                |}\n            \"\"\".trimMargin(),\n            DiktatError(1, 1, ruleId, \"${COMMENTED_OUT_CODE.warnText()} import org.junit.Ignore\", false),\n            DiktatError(6, 5, ruleId, \"${COMMENTED_OUT_CODE.warnText()} fun foo(a: Int): Int {\", false)\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.COMMENTED_OUT_CODE)\n    @Suppress(\"TOO_LONG_FUNCTION\", \"LongMethod\")\n    fun `very long commented code`() {\n        lintMethod(\n            \"\"\"\n                |class ScheduleTest {\n                |/*\n                |   fun clickFilters_showFilters() {\n                |       checkAnimationsDisabled()\n                |\n                |       onView(withId(R.id.filter_fab)).perform(click())\n                |\n                |       val uncheckedFilterContentDesc =\n                |           getDisabledFilterContDesc(FakeConferenceDataSource.FAKE_SESSION_TAG_NAME)\n                |       val checkedFilterContentDesc =\n                |           getActiveFilterContDesc(FakeConferenceDataSource.FAKE_SESSION_TAG_NAME)\n                |\n                |       // Scroll to the filter\n                |       onView(allOf(withId(R.id.recyclerview_filter), withParent(withId(R.id.filter_sheet))))\n                |           .perform(\n                |               RecyclerViewActions.scrollTo<ScheduleFilterAdapter.FilterViewHolder>(\n                |                   withContentDescription(uncheckedFilterContentDesc)\n                |               )\n                |           )\n                |\n                |       onView(withContentDescription(uncheckedFilterContentDesc))\n                |           .check(matches(isDisplayed()))\n                |           .perform(click())\n                |\n                |       // Check that the filter is enabled\n                |       onView(\n                |           allOf(\n                |               withId(R.id.filter_label),\n                |               withContentDescription(checkedFilterContentDesc),\n                |               not(withParent(withId(R.id.filter_description_tags)))\n                |           )\n                |       )\n                |           .check(matches(isDisplayed()))\n                |           .perform(click())\n                |   }\n                |\n                |   private fun applyFilter(filter: String) {\n                |       // Open the filters sheet\n                |       onView(withId(R.id.filter_fab)).perform(click())\n                |\n                |       // Get the content description of the view we need to click on\n                |       val uncheckedFilterContentDesc =\n                |           resources.getString(R.string.a11y_filter_not_applied, filter)\n                |\n                |      onView(allOf(withId(R.id.recyclerview_filter), withParent(withId(R.id.filter_sheet))))\n                |          .check(matches(isDisplayed()))\n                |\n                |       // Scroll to the filter\n                |       onView(allOf(withId(R.id.recyclerview_filter), withParent(withId(R.id.filter_sheet))))\n                |         .perform(\n                |             RecyclerViewActions.scrollTo<ScheduleFilterAdapter.FilterViewHolder>(\n                |                 withContentDescription(uncheckedFilterContentDesc)\n                |             )\n                |         )\n                |   }\n                |   */\n                |}\n            \"\"\".trimMargin(),\n            DiktatError(2, 1, ruleId, \"${COMMENTED_OUT_CODE.warnText()} fun clickFilters_showFilters() {\", false)\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.COMMENTED_OUT_CODE)\n    fun `Should warn if detects commented out code example with IDEA style indents`() {\n        lintMethod(\n            \"\"\"\n                |//import org.junit.Ignore\n                |import org.junit.Test\n                |\n                |class Example {\n                |    // this function is disabled for now\n                |//    fun foo(a: Int): Int {\n                |//        println(a + 42)\n                |//        println(\"This is a test string\")\n                |//        return 0\n                |//    }\n                |}\n            \"\"\".trimMargin(),\n            DiktatError(1, 1, ruleId, \"${COMMENTED_OUT_CODE.warnText()} import org.junit.Ignore\", false),\n            DiktatError(6, 1, ruleId, \"${COMMENTED_OUT_CODE.warnText()} fun foo(a: Int): Int {\", false)\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.COMMENTED_OUT_CODE)\n    fun `should trigger on class with one space after comment start token`() {\n        lintMethod(\n            \"\"\"\n                |// class Test: Exception()\n            \"\"\".trimMargin())\n    }\n\n    @Test\n    @Tag(WarningNames.COMMENTED_OUT_CODE)\n    fun `should trigger on class with one space after comment start token and 2 modifiers #1`() {\n        lintMethod(\n            \"\"\"\n                |// public data class Test(val some: Int): Exception()\n            \"\"\".trimMargin(),\n            DiktatError(1, 1, ruleId, \"${COMMENTED_OUT_CODE.warnText()} public data class Test(val some: Int): Exception()\", false))\n    }\n\n    @Test\n    @Tag(WarningNames.COMMENTED_OUT_CODE)\n    fun `should trigger on one-line comment with var or val`() {\n        lintMethod(\n            \"\"\"\n                |// var foo: Int = 1\n            \"\"\".trimMargin(),\n            DiktatError(1, 1, ruleId, \"${COMMENTED_OUT_CODE.warnText()} var foo: Int = 1\", false))\n    }\n\n    @Test\n    @Tag(WarningNames.COMMENTED_OUT_CODE)\n    fun `should trigger on one-line multi comment`() {\n        lintMethod(\n            \"\"\"\n                | // fun foo() {\n                | //     varfoo adda foofoo\n                | // }\n            \"\"\".trimMargin(),\n            DiktatError(1, 2, ruleId, \"${COMMENTED_OUT_CODE.warnText()} fun foo() {\", false))\n    }\n\n    @Test\n    @Tag(WarningNames.COMMENTED_OUT_CODE)\n    fun `should trigger on one-line comment`() {\n        lintMethod(\n            \"\"\"\n                | // class A { val a = 2 }\n            \"\"\".trimMargin(),\n            DiktatError(1, 2, ruleId, \"${COMMENTED_OUT_CODE.warnText()} class A { val a = 2 }\", false))\n    }\n\n    @Test\n    @Tag(WarningNames.COMMENTED_OUT_CODE)\n    fun `should trigger on one-line block comment`() {\n        lintMethod(\n            \"\"\"\n                | /* class A { val a = 2 } */\n            \"\"\".trimMargin(),\n            DiktatError(1, 2, ruleId, \"${COMMENTED_OUT_CODE.warnText()} class A { val a = 2 }\", false))\n    }\n\n    @Test\n    @Tag(WarningNames.COMMENTED_OUT_CODE)\n    fun `should trigger on class with one space after comment start token and 2 modifiers #2`() {\n        lintMethod(\n            \"\"\"\n                |// internal sealed class Test: Exception()\n            \"\"\".trimMargin())\n    }\n\n    @Test\n    @Tag(WarningNames.COMMENTED_OUT_CODE)\n    fun `should trigger on import with one space after comment start token`() {\n        lintMethod(\n            \"\"\"\n                |// import some.org\n            \"\"\".trimMargin(),\n            DiktatError(1, 1, ruleId, \"${COMMENTED_OUT_CODE.warnText()} import some.org\", false))\n    }\n\n    @Test\n    @Tag(WarningNames.COMMENTED_OUT_CODE)\n    fun `should trigger on package with one space after comment start token`() {\n        lintMethod(\n            \"\"\"\n                |// package some.org\n            \"\"\".trimMargin(),\n            DiktatError(1, 1, ruleId, \"${COMMENTED_OUT_CODE.warnText()} package some.org\", false))\n    }\n\n    @Test\n    @Tag(WarningNames.COMMENTED_OUT_CODE)\n    fun `should trigger on function with one space after comment start token - { sign`() {\n        lintMethod(\n            \"\"\"\n                |// fun someFunc(name: String): Boolean {\n                |//     val a = 5\n                |// }\n            \"\"\".trimMargin(),\n            DiktatError(1, 1, ruleId, \"${COMMENTED_OUT_CODE.warnText()} fun someFunc(name: String): Boolean {\", false))\n    }\n\n    @Test\n    @Tag(WarningNames.COMMENTED_OUT_CODE)\n    fun `should trigger on function with one space after comment start token - = sign`() {\n        lintMethod(\n            \"\"\"\n                |// fun someFunc(name: String): Boolean =\n                |//     name.contains(\"a\")\n            \"\"\".trimMargin(),\n            DiktatError(1, 1, ruleId, \"${COMMENTED_OUT_CODE.warnText()} fun someFunc(name: String): Boolean =\", false))\n    }\n\n    @Test\n    @Tag(WarningNames.COMMENTED_OUT_CODE)\n    fun `should trigger on function with one space after comment start token pulbic modifier`() {\n        lintMethod(\n            \"\"\"\n                |// public fun someFunc(name: String): Boolean =\n                |//     name.contains(\"a\")\n            \"\"\".trimMargin(),\n            DiktatError(1, 1, ruleId, \"${COMMENTED_OUT_CODE.warnText()} public fun someFunc(name: String): Boolean =\", false))\n    }\n\n    @Test\n    @Tag(WarningNames.COMMENTED_OUT_CODE)\n    fun `should not trigger on multiline comments #1`() {\n        lintMethod(\n            \"\"\"\n                |/*\n                |\n                |   Copyright 2018-2020 John Doe.\n                |\n                |   Licensed under the Apache License, Version 2.0 (the \"License\");\n                |   you may not use this file except in compliance with the License.\n                |   You may obtain a copy of the License at\n                |\n                |       http://www.apache.org/licenses/LICENSE-2.0\n                |\n                |   Unless required by applicable law or agreed to in writing, software\n                |   distributed under the License is distributed on an \"AS IS\" BASIS,\n                |   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n                |   See the License for the specific language governing permissions and\n                |   limitations under the License.\n                |\n                |*/\n            \"\"\".trimMargin())\n    }\n\n    @Test\n    @Tag(WarningNames.COMMENTED_OUT_CODE)\n    fun `should not trigger on multiline comments #2`() {\n        lintMethod(\n            \"\"\"\n                |   /*\n                |   * some text here\n                |   maybe even with another line\n                |   */\n            \"\"\".trimMargin())\n    }\n\n    @Test\n    @Tag(WarningNames.COMMENTED_OUT_CODE)\n    fun `should not trigger on Copyright and another comment`() {\n        lintMethod(\n            \"\"\"\n            /*\n                Copyright (c) Your Company Name Here. 2010-2021\n            */\n\n            package com.saveourtool.diktat\n\n            /*\n                x = 2 + 4 + 1\n            */\n            // x = 2+4\n\n            // if true make this\n\n            /*\n                class A {\n\n                fun foo()\n\n                }\n\n            */\n            \"\"\".trimMargin(),\n            DiktatError(7, 13, ruleId, \"${COMMENTED_OUT_CODE.warnText()} x = 2 + 4 + 1\", false),\n            DiktatError(14, 13, ruleId, \"${COMMENTED_OUT_CODE.warnText()} class A {\", false)\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.COMMENTED_OUT_CODE)\n    fun `should not trigger with suppress`() {\n        lintMethod(\n            \"\"\"\n            @Suppress(\"UnsafeCallOnNullableType\", \"COMMENTED_OUT_CODE\")\n            private fun handleProperty(property: KtProperty) {\n\n             /*\n                x = 1\n             */\n            }\n\n            @Suppress(\"COMMENTED_OUT_CODE\")\n            class A {\n                // val x = 10\n            }\n            \"\"\".trimMargin()\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.COMMENTED_OUT_CODE)\n    fun `should not trigger on 'imports'`() {\n        lintMethod(\n            \"\"\"\n            /* Checks if specified imports can be found in classpath. */\n            class Example\n\n            /* Checks if specified import can be found in classpath. */\n            class Example2\n\n            /* import this and you died. */\n            class Example3\n            \"\"\".trimMargin()\n        )\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/test/kotlin/com/saveourtool/diktat/ruleset/chapter3/AnnotationNewLineRuleFixTest.kt",
    "content": "package com.saveourtool.diktat.ruleset.chapter3\n\nimport com.saveourtool.diktat.ruleset.rules.chapter3.AnnotationNewLineRule\nimport com.saveourtool.diktat.util.FixTestBase\n\nimport generated.WarningNames\nimport org.junit.jupiter.api.Tag\nimport org.junit.jupiter.api.Test\n\nclass AnnotationNewLineRuleFixTest : FixTestBase(\"test/paragraph3/annotations\", ::AnnotationNewLineRule) {\n    @Test\n    @Tag(WarningNames.ANNOTATION_NEW_LINE)\n    fun `should fix func and class annotations`() {\n        fixAndCompare(\"AnnotationSingleLineExpected.kt\", \"AnnotationSingleLineTest.kt\")\n    }\n\n    @Test\n    @Tag(WarningNames.ANNOTATION_NEW_LINE)\n    fun `should fix constructor annotations`() {\n        fixAndCompare(\"AnnotationConstructorSingleLineExpected.kt\", \"AnnotationConstructorSingleLineTest.kt\")\n    }\n\n    @Test\n    @Tag(WarningNames.ANNOTATION_NEW_LINE)\n    fun `shouldn't fix correct annotation with comment`() {\n        fixAndCompare(\"AnnotationCommentExpected.kt\", \"AnnotationCommentTest.kt\")\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/test/kotlin/com/saveourtool/diktat/ruleset/chapter3/AnnotationNewLineRuleWarnTest.kt",
    "content": "package com.saveourtool.diktat.ruleset.chapter3\n\nimport com.saveourtool.diktat.common.config.rules.DIKTAT_RULE_SET_ID\nimport com.saveourtool.diktat.ruleset.constants.Warnings\nimport com.saveourtool.diktat.ruleset.rules.chapter3.AnnotationNewLineRule\nimport com.saveourtool.diktat.util.LintTestBase\n\nimport com.saveourtool.diktat.api.DiktatError\nimport generated.WarningNames\nimport org.junit.jupiter.api.Tag\nimport org.junit.jupiter.api.Test\n\nclass AnnotationNewLineRuleWarnTest : LintTestBase(::AnnotationNewLineRule) {\n    private val ruleId = \"$DIKTAT_RULE_SET_ID:${AnnotationNewLineRule.NAME_ID}\"\n\n    @Test\n    @Tag(WarningNames.ANNOTATION_NEW_LINE)\n    fun `annotation class test good`() {\n        lintMethod(\n            \"\"\"\n                    |@SomeAnnotation\n                    |@SecondAnnotation\n                    |class A {\n                    |   val a = 5\n                    |}\n            \"\"\".trimMargin()\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.ANNOTATION_NEW_LINE)\n    fun `annotation class test good 2`() {\n        lintMethod(\n            \"\"\"\n                    |@SomeAnnotation class A {\n                    |   val a = 5\n                    |}\n            \"\"\".trimMargin()\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.ANNOTATION_NEW_LINE)\n    fun `annotation class test bad`() {\n        lintMethod(\n            \"\"\"\n                    |@SomeAnnotation @SecondAnnotation\n                    |class A {\n                    |   val a = 5\n                    |}\n            \"\"\".trimMargin(),\n            DiktatError(1, 1, ruleId, \"${Warnings.ANNOTATION_NEW_LINE.warnText()} @SomeAnnotation not on a single line\", true),\n            DiktatError(1, 17, ruleId, \"${Warnings.ANNOTATION_NEW_LINE.warnText()} @SecondAnnotation not on a single line\", true)\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.ANNOTATION_NEW_LINE)\n    fun `annotation class test bad 2`() {\n        lintMethod(\n            \"\"\"\n                    |@SomeAnnotation @SecondAnnotation class A {\n                    |   val a = 5\n                    |}\n            \"\"\".trimMargin(),\n            DiktatError(1, 1, ruleId, \"${Warnings.ANNOTATION_NEW_LINE.warnText()} @SomeAnnotation not on a single line\", true),\n            DiktatError(1, 17, ruleId, \"${Warnings.ANNOTATION_NEW_LINE.warnText()} @SecondAnnotation not on a single line\", true)\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.ANNOTATION_NEW_LINE)\n    fun `annotation fun test good`() {\n        lintMethod(\n            \"\"\"\n                    |class A {\n                    |   val a = 5\n                    |\n                    |  @SomeAnnotation\n                    |  @SecondAnnotation\n                    |  fun someFunc() {\n                    |       val a = 3\n                    |  }\n                    |}\n            \"\"\".trimMargin()\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.ANNOTATION_NEW_LINE)\n    fun `annotation fun test good 2`() {\n        lintMethod(\n            \"\"\"\n                    |class A {\n                    |   val a = 5\n                    |\n                    |  @SomeAnnotation fun someFunc() {\n                    |       val a = 3\n                    |  }\n                    |}\n            \"\"\".trimMargin()\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.ANNOTATION_NEW_LINE)\n    fun `annotation fun test bad`() {\n        lintMethod(\n            \"\"\"\n                    |class A {\n                    |   val a = 5\n                    |\n                    |  @SomeAnnotation @SecondAnnotation fun someFunc() {\n                    |       val a = 3\n                    |  }\n                    |}\n            \"\"\".trimMargin(),\n            DiktatError(4, 3, ruleId, \"${Warnings.ANNOTATION_NEW_LINE.warnText()} @SomeAnnotation not on a single line\", true),\n            DiktatError(4, 19, ruleId, \"${Warnings.ANNOTATION_NEW_LINE.warnText()} @SecondAnnotation not on a single line\", true)\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.ANNOTATION_NEW_LINE)\n    fun `annotation fun test bad 2`() {\n        lintMethod(\n            \"\"\"\n                    |class A {\n                    |   val a = 5\n                    |\n                    |  @SomeAnnotation @SecondAnnotation\n                    |  fun someFunc() {\n                    |       val a = 3\n                    |  }\n                    |}\n            \"\"\".trimMargin(),\n            DiktatError(4, 3, ruleId, \"${Warnings.ANNOTATION_NEW_LINE.warnText()} @SomeAnnotation not on a single line\", true),\n            DiktatError(4, 19, ruleId, \"${Warnings.ANNOTATION_NEW_LINE.warnText()} @SecondAnnotation not on a single line\", true)\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.ANNOTATION_NEW_LINE)\n    fun `annotation constructor test good`() {\n        lintMethod(\n            \"\"\"\n                    |public class Conf\n                    |@Inject\n                    |constructor(conf: Int) {\n                    |\n                    |}\n            \"\"\".trimMargin()\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.ANNOTATION_NEW_LINE)\n    fun `annotation constructor test good 2`() {\n        lintMethod(\n            \"\"\"\n                    |public class Conf @Inject constructor(conf: Int) {\n                    |\n                    |}\n            \"\"\".trimMargin()\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.ANNOTATION_NEW_LINE)\n    fun `annotation constructor test good 3`() {\n        lintMethod(\n            \"\"\"\n                    |public class Conf\n                    |@Inject\n                    |@SomeAnnotation\n                    |constructor(conf: Int) {\n                    |\n                    |}\n            \"\"\".trimMargin()\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.ANNOTATION_NEW_LINE)\n    fun `annotation secondary constructor test good`() {\n        lintMethod(\n            \"\"\"\n                    |public class Conf {\n                    |   @FirstAnnotation constructor(conf: Conf) {\n                    |\n                    |   }\n                    |}\n            \"\"\".trimMargin()\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.ANNOTATION_NEW_LINE)\n    fun `annotation secondary constructor test bad`() {\n        lintMethod(\n            \"\"\"\n                    |public class Conf {\n                    |   @FirstAnnotation @SecondAnnotation constructor(conf: Conf) {\n                    |\n                    |   }\n                    |}\n            \"\"\".trimMargin(),\n            DiktatError(2, 4, ruleId, \"${Warnings.ANNOTATION_NEW_LINE.warnText()} @FirstAnnotation not on a single line\", true),\n            DiktatError(2, 21, ruleId, \"${Warnings.ANNOTATION_NEW_LINE.warnText()} @SecondAnnotation not on a single line\", true)\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.ANNOTATION_NEW_LINE)\n    fun `annotation constructor test bad`() {\n        lintMethod(\n            \"\"\"\n                    |public class Conf @Inject @SomeAnnotation constructor(conf: Int) {\n                    |\n                    |}\n            \"\"\".trimMargin(),\n            DiktatError(1, 19, ruleId, \"${Warnings.ANNOTATION_NEW_LINE.warnText()} @Inject not on a single line\", true),\n            DiktatError(1, 27, ruleId, \"${Warnings.ANNOTATION_NEW_LINE.warnText()} @SomeAnnotation not on a single line\", true)\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.ANNOTATION_NEW_LINE)\n    fun `annotation constructor test bad 2`() {\n        lintMethod(\n            \"\"\"\n                    |public class Conf @Inject\n                    |@SomeAnnotation constructor(conf: Int) {\n                    |\n                    |}\n            \"\"\".trimMargin(),\n            DiktatError(1, 19, ruleId, \"${Warnings.ANNOTATION_NEW_LINE.warnText()} @Inject not on a single line\", true),\n            DiktatError(2, 1, ruleId, \"${Warnings.ANNOTATION_NEW_LINE.warnText()} @SomeAnnotation not on a single line\", true)\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.ANNOTATION_NEW_LINE)\n    fun `no warns in func params`() {\n        lintMethod(\n            \"\"\"\n                    |public class Conf {\n                    |   fun someFunc(@SomeAnnotation conf: JsonConf, @SecondAnnotation some: Int) {\n                    |\n                    |   }\n                    |}\n            \"\"\".trimMargin()\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.ANNOTATION_NEW_LINE)\n    fun `no warns in func params 2`() {\n        lintMethod(\n            \"\"\"\n                    |public class Conf {\n                    |   fun someFunc(@SomeAnnotation @AnotherAnnotation conf: JsonConf, @SecondAnnotation @ThirdAnnotation some: Int) {\n                    |\n                    |   }\n                    |}\n            \"\"\".trimMargin()\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.ANNOTATION_NEW_LINE)\n    fun `no warn in correct annotation with comment`() {\n        lintMethod(\n            \"\"\"\n                    |@ExperimentalStdlibApi  // to use `scan` on sequence\n                    |   @Suppress(\"WRONG_NEWLINES\")\n                    |   override fun checkNode() {}\n            \"\"\".trimMargin()\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.ANNOTATION_NEW_LINE)\n    fun `should warn annotation for several annotations`() {\n        lintMethod(\n            \"\"\"\n                    |@ExperimentalStdlibApi /*   */ @Hello\n                    |override fun checkNode() {}\n                    |\n                    |/*    */ @Goo\n                    |class A {}\n                    |\n                    |@A1\n                    |/*   */ @A2\n                    |@A3\n                    |class A {}\n                    |\n                    |\n                    |@Foo class Foo {}\n                    |\n                    |@Foo\n                    |class Foo {}\n                    |\n                    |@Foo @Goo val loader: DataLoader\n                    |\n                    |@Foo\n                    |@goo val loader: DataLoader\n            \"\"\".trimMargin(),\n            DiktatError(1, 1, ruleId, \"${Warnings.ANNOTATION_NEW_LINE.warnText()} @ExperimentalStdlibApi not on a single line\", true),\n            DiktatError(1, 32, ruleId, \"${Warnings.ANNOTATION_NEW_LINE.warnText()} @Hello not on a single line\", true),\n        )\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/test/kotlin/com/saveourtool/diktat/ruleset/chapter3/BlockStructureBracesFixTest.kt",
    "content": "package com.saveourtool.diktat.ruleset.chapter3\n\nimport com.saveourtool.diktat.ruleset.rules.chapter3.BlockStructureBraces\nimport com.saveourtool.diktat.util.FixTestBase\n\nimport generated.WarningNames\nimport org.junit.jupiter.api.Tag\nimport org.junit.jupiter.api.Test\n\nclass BlockStructureBracesFixTest : FixTestBase (\"test/paragraph3/block_brace\", ::BlockStructureBraces) {\n    @Test\n    @Tag(WarningNames.BRACES_BLOCK_STRUCTURE_ERROR)\n    fun `should fix open and close brace in if-else expression`() {\n        fixAndCompare(\"IfElseBracesExpected.kt\", \"IfElseBracesTest.kt\")\n    }\n\n    @Test\n    @Tag(WarningNames.BRACES_BLOCK_STRUCTURE_ERROR)\n    fun `should fix open and close brace in class expression`() {\n        fixAndCompare(\"ClassBracesExpected.kt\", \"ClassBracesTest.kt\")\n    }\n\n    @Test\n    @Tag(WarningNames.BRACES_BLOCK_STRUCTURE_ERROR)\n    fun `should fix open and close brace in do-while expression`() {\n        fixAndCompare(\"DoWhileBracesExpected.kt\", \"DoWhileBracesTest.kt\")\n    }\n\n    @Test\n    @Tag(WarningNames.BRACES_BLOCK_STRUCTURE_ERROR)\n    fun `should fix open and close brace in loops expression`() {\n        fixAndCompare(\"LoopsBracesExpected.kt\", \"LoopsBracesTest.kt\")\n    }\n\n    @Test\n    @Tag(WarningNames.BRACES_BLOCK_STRUCTURE_ERROR)\n    fun `should fix open and close brace in when expression`() {\n        fixAndCompare(\"WhenBranchesExpected.kt\", \"WhenBranchesTest.kt\")\n    }\n\n    @Test\n    @Tag(WarningNames.BRACES_BLOCK_STRUCTURE_ERROR)\n    fun `should fix open and close brace in try-catch-finally expression`() {\n        fixAndCompare(\"TryBraceExpected.kt\", \"TryBraceTest.kt\")\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/test/kotlin/com/saveourtool/diktat/ruleset/chapter3/BlockStructureBracesWarnTest.kt",
    "content": "package com.saveourtool.diktat.ruleset.chapter3\n\nimport com.saveourtool.diktat.common.config.rules.DIKTAT_RULE_SET_ID\nimport com.saveourtool.diktat.common.config.rules.RulesConfig\nimport com.saveourtool.diktat.ruleset.constants.Warnings.BRACES_BLOCK_STRUCTURE_ERROR\nimport com.saveourtool.diktat.ruleset.rules.chapter3.BlockStructureBraces\nimport com.saveourtool.diktat.util.LintTestBase\n\nimport com.saveourtool.diktat.api.DiktatError\nimport generated.WarningNames\nimport org.junit.jupiter.api.Tag\nimport org.junit.jupiter.api.Test\n\nclass BlockStructureBracesWarnTest : LintTestBase(::BlockStructureBraces) {\n    private val ruleId = \"$DIKTAT_RULE_SET_ID:${BlockStructureBraces.NAME_ID}\"\n    private val rulesConfigList: List<RulesConfig> = listOf(\n        RulesConfig(BRACES_BLOCK_STRUCTURE_ERROR.name, true,\n            mapOf(\"openBraceNewline\" to \"False\", \"closeBraceNewline\" to \"False\"))\n    )\n    private val rulesConfigListIgnoreOpen: List<RulesConfig> = listOf(\n        RulesConfig(BRACES_BLOCK_STRUCTURE_ERROR.name, true,\n            mapOf(\"openBraceNewline\" to \"False\"))\n    )\n    private val rulesConfigListIgnoreClose: List<RulesConfig> = listOf(\n        RulesConfig(BRACES_BLOCK_STRUCTURE_ERROR.name, true,\n            mapOf(\"closeBraceNewline\" to \"False\"))\n    )\n\n    @Test\n    @Tag(WarningNames.BRACES_BLOCK_STRUCTURE_ERROR)\n    fun `check if expression with new line else`() {\n        lintMethod(\n            \"\"\"\n                    |fun foo() {\n                    |    if (x < -5) {\n                    |       goo()\n                    |    }\n                    |    else {\n                    |       koo()}\n                    |}\n            \"\"\".trimMargin(),\n            DiktatError(4, 6, ruleId, \"${BRACES_BLOCK_STRUCTURE_ERROR.warnText()} incorrect new line after closing brace\", true),\n            DiktatError(6, 13, ruleId, \"${BRACES_BLOCK_STRUCTURE_ERROR.warnText()} no newline before closing brace\", true)\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.BRACES_BLOCK_STRUCTURE_ERROR)\n    fun `correct if expression without else`() {\n        val withBrace =\n            \"\"\"\n                |fun foo() {\n                |   if (x > 5) {\n                |       x--\n                |   }\n                |}\n            \"\"\".trimMargin()\n        lintMethod(withBrace)\n\n        val withoutBrace =\n            \"\"\"\n                |fun foo() {\n                |   if (x > 5)\n                |       x--\n                |}\n            \"\"\".trimMargin()\n        lintMethod(withoutBrace)\n    }\n\n    @Test\n    @Tag(WarningNames.BRACES_BLOCK_STRUCTURE_ERROR)\n    fun `check correct if with else-if expression`() {\n        lintMethod(\n            \"\"\"\n                    |fun foo() {\n                    |    if (x < -5) {\n                    |       goo()\n                    |    } else if (x > 5) {\n                    |       hoo()\n                    |    } else {\n                    |       koo()\n                    |    }\n                    |}\n            \"\"\".trimMargin()\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.BRACES_BLOCK_STRUCTURE_ERROR)\n    fun `check lambda with empty block`() {\n        lintMethod(\n            \"\"\"\n                    |fun foo() {\n                    |   run {\n                    |\n                    |   }\n                    |}\n            \"\"\".trimMargin()\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.BRACES_BLOCK_STRUCTURE_ERROR)\n    fun `check empty block in else expression`() {\n        lintMethod(\n            \"\"\"\n                    |fun foo() {\n                    |    if (x < -5) {\n                    |       goo()\n                    |    } else if (x > 5) {\n                    |       hoo()\n                    |    } else {\n                    |    }\n                    |}\n            \"\"\".trimMargin()\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.BRACES_BLOCK_STRUCTURE_ERROR)\n    fun `check wrong empty block in if expression`() {\n        lintMethod(\n            \"\"\"\n                    |fun foo() {\n                    |    if (x < -5) {\n                    |       goo()\n                    |    } else {}\n                    |}\n            \"\"\".trimMargin(),\n            DiktatError(4, 13, ruleId, \"${BRACES_BLOCK_STRUCTURE_ERROR.warnText()} incorrect same line after opening brace\", true),\n            DiktatError(4, 13, ruleId, \"${BRACES_BLOCK_STRUCTURE_ERROR.warnText()} no newline before closing brace\", true)\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.BRACES_BLOCK_STRUCTURE_ERROR)\n    fun `check if expression with wrong opening brace position`() {\n        lintMethod(\n            \"\"\"\n                    |fun foo() {\n                    |    if (x < -5)\n                    |    {\n                    |       bf()\n                    |    } else { f()\n                    |    }\n                    |}\n            \"\"\".trimMargin(),\n            DiktatError(2, 16, ruleId, \"${BRACES_BLOCK_STRUCTURE_ERROR.warnText()} incorrect newline before opening brace\", true),\n            DiktatError(5, 13, ruleId, \"${BRACES_BLOCK_STRUCTURE_ERROR.warnText()} incorrect same line after opening brace\", true)\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.BRACES_BLOCK_STRUCTURE_ERROR)\n    fun `check if expression with wrong closing brace position`() {\n        lintMethod(\n            \"\"\"\n                    |fun foo() {\n                    |    if (x < -5) {\n                    |       bf() }\n                    |    else {\n                    |       f() }\n                    |}\n            \"\"\".trimMargin(),\n            DiktatError(3, 13, ruleId, \"${BRACES_BLOCK_STRUCTURE_ERROR.warnText()} no newline before closing brace\", true),\n            DiktatError(3, 14, ruleId, \"${BRACES_BLOCK_STRUCTURE_ERROR.warnText()} incorrect new line after closing brace\", true),\n            DiktatError(5, 12, ruleId, \"${BRACES_BLOCK_STRUCTURE_ERROR.warnText()} no newline before closing brace\", true)\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.BRACES_BLOCK_STRUCTURE_ERROR)\n    fun `check wrong brace in if expression but with off configuration`() {\n        lintMethod(\n            \"\"\"\n                    |fun foo() {\n                    |    if (x < -5)\n                    |    {\n                    |       goo() }\n                    |    else\n                    |    {\n                    |       hoo() }\n                    |}\n            \"\"\".trimMargin(),\n            DiktatError(4, 15, ruleId, \"${BRACES_BLOCK_STRUCTURE_ERROR.warnText()} incorrect new line after closing brace\", true),\n            rulesConfigList = rulesConfigList\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.BRACES_BLOCK_STRUCTURE_ERROR)\n    fun `check function expression with wrong open brace with configuration`() {\n        lintMethod(\n            \"\"\"\n                    |fun foo()\n                    |{\n                    |   pyu()\n                    |}\n            \"\"\".trimMargin(), rulesConfigList = rulesConfigListIgnoreOpen\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.BRACES_BLOCK_STRUCTURE_ERROR)\n    fun `check empty fun expression with override annotation`() {\n        lintMethod(\n            \"\"\"\n                    |override fun foo() {\n                    |}\n            \"\"\".trimMargin()\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.BRACES_BLOCK_STRUCTURE_ERROR)\n    fun `check one line fun`() {\n        lintMethod(\n            \"\"\"\n                    |fun foo() = 0\n            \"\"\".trimMargin()\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.BRACES_BLOCK_STRUCTURE_ERROR)\n    fun `check fun with empty block won't be processed`() {\n        lintMethod(\n            \"\"\"\n                    |fun foo() {}\n            \"\"\".trimMargin()\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.BRACES_BLOCK_STRUCTURE_ERROR)\n    fun `check function expression with wrong close brace`() {\n        lintMethod(\n            \"\"\"\n                    |fun foo() {\n                    |   pyu() }\n            \"\"\".trimMargin(),\n            DiktatError(2, 10, ruleId, \"${BRACES_BLOCK_STRUCTURE_ERROR.warnText()} no newline before closing brace\", true)\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.BRACES_BLOCK_STRUCTURE_ERROR)\n    fun `check simple wrong open brace when expression`() {\n        lintMethod(\n            \"\"\"\n                    |fun a(x: Int) {\n                    |   when (x)\n                    |   {\n                    |       1 -> println(2)\n                    |       else -> println(\"df\")\n                    |   }\n                    |}\n            \"\"\".trimMargin(),\n            DiktatError(2, 12, ruleId, \"${BRACES_BLOCK_STRUCTURE_ERROR.warnText()} incorrect newline before opening brace\", true)\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.BRACES_BLOCK_STRUCTURE_ERROR)\n    fun `check correct simple for without brace `() {\n        lintMethod(\n            \"\"\"\n                    |fun a(x: Int) {\n                    |   for (i in 1..3)\n                    |       println(i)\n                    |}\n            \"\"\".trimMargin()\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.BRACES_BLOCK_STRUCTURE_ERROR)\n    fun `check wrong for expression with empty block but with config`() {\n        lintMethod(\n            \"\"\"\n                    |fun a(x: Int) {\n                    |   for (i in 1..3) {}\n                    |}\n            \"\"\".trimMargin()\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.BRACES_BLOCK_STRUCTURE_ERROR)\n    fun `check correct while without brace`() {\n        lintMethod(\n            \"\"\"\n                    |fun sdf() {\n                    |   while (x > 0)\n                    |       x--\n                    |}\n            \"\"\".trimMargin()\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.BRACES_BLOCK_STRUCTURE_ERROR)\n    fun `check wrong do-while with open brace`() {\n        lintMethod(\n            \"\"\"\n                    |fun sdf() {\n                    |   do\n                    |   {\n                    |       x--\n                    |   } while (x != 0)\n                    |}\n            \"\"\".trimMargin(),\n            DiktatError(2, 6, ruleId, \"${BRACES_BLOCK_STRUCTURE_ERROR.warnText()} incorrect newline before opening brace\", true)\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.BRACES_BLOCK_STRUCTURE_ERROR)\n    fun `check try-catch-finally with wrong position catch and finally words `() {\n        lintMethod(\n            \"\"\"\n                    |fun divideOrZero(numerator: Int, denominator: Int): Int {\n                    |   try {\n                    |       return numerator / denominator\n                    |   } catch (e: ArithmeticException) {\n                    |       return 0\n                    |   }\n                    |   catch (e: Exception) {\n                    |       return 1\n                    |   }\n                    |   finally {\n                    |       println(\"Hello\")\n                    |   }\n                    |}\n            \"\"\".trimMargin(),\n            DiktatError(6, 5, ruleId, \"${BRACES_BLOCK_STRUCTURE_ERROR.warnText()} incorrect new line after closing brace\", true),\n            DiktatError(9, 5, ruleId, \"${BRACES_BLOCK_STRUCTURE_ERROR.warnText()} incorrect new line after closing brace\", true)\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.BRACES_BLOCK_STRUCTURE_ERROR)\n    fun `check wrong try-catch with open and close braces`() {\n        lintMethod(\n            \"\"\"\n                    |fun divideOrZero(numerator: Int, denominator: Int): Int {\n                    |   try { return numerator / denominator\n                    |   } catch (e: ArithmeticException) {\n                    |       return 0\n                    |   } catch (e: Exception) {\n                    |       return 1 }\n                    |}\n            \"\"\".trimMargin(),\n            DiktatError(2, 9, ruleId, \"${BRACES_BLOCK_STRUCTURE_ERROR.warnText()} incorrect same line after opening brace\", true),\n            DiktatError(6, 17, ruleId, \"${BRACES_BLOCK_STRUCTURE_ERROR.warnText()} no newline before closing brace\", true)\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.BRACES_BLOCK_STRUCTURE_ERROR)\n    fun `check correct simple class expression`() {\n        lintMethod(\n            \"\"\"\n                    |class A {\n                    |   fun foo() {\n                    |       println(\"Hello\")\n                    |   }\n                    |}\n            \"\"\".trimMargin()\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.BRACES_BLOCK_STRUCTURE_ERROR)\n    fun `check wrong simple class expression but with config`() {\n        lintMethod(\n            \"\"\"\n                    |class A\n                    |{\n                    |   fun foo() {\n                    |       println(\"Hello\")\n                    |   } }\n            \"\"\".trimMargin(), rulesConfigList = rulesConfigList\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.BRACES_BLOCK_STRUCTURE_ERROR)\n    fun `check wrong close brace in object expression but with ignore config`() {\n        lintMethod(\n            \"\"\"\n                    |object A {\n                    |   fun foo() {\n                    |       println(\"Hello\")\n                    |   }\n                    |\n                    |   val x: Int = 10 }\n            \"\"\".trimMargin(), rulesConfigList = rulesConfigListIgnoreClose\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.BRACES_BLOCK_STRUCTURE_ERROR)\n    fun `check wrong open brace in object expression`() {\n        lintMethod(\n            \"\"\"\n                    |object A\n                    |{\n                    |   fun foo() {\n                    |       println(\"Hello\")\n                    |   }\n                    |\n                    |   val x: Int = 10\n                    |}\n            \"\"\".trimMargin(),\n            DiktatError(1, 9, ruleId, \"${BRACES_BLOCK_STRUCTURE_ERROR.warnText()} incorrect newline before opening brace\", true)\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.BRACES_BLOCK_STRUCTURE_ERROR)\n    fun `check init expression with wrong opening and closing brace position `() {\n        lintMethod(\n            \"\"\"\n                    |class A {\n                    |   init\n                    |   {\n                    |       foo() }\n                    |\n                    |   fun foo() {\n                    |       println(\"Hello\")\n                    |   }\n                    |}\n            \"\"\".trimMargin(),\n            DiktatError(2, 8, ruleId, \"${BRACES_BLOCK_STRUCTURE_ERROR.warnText()} incorrect newline before opening brace\", true),\n            DiktatError(4, 14, ruleId, \"${BRACES_BLOCK_STRUCTURE_ERROR.warnText()} no newline before closing brace\", true)\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.BRACES_BLOCK_STRUCTURE_ERROR)\n    fun `check correct simple constructor expression`() {\n        lintMethod(\n            \"\"\"\n                    |class Person() {\n                    |   constructor(id: Int) {\n                    |       println(id)\n                    |   }\n                    |}\n            \"\"\".trimMargin()\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.BRACES_BLOCK_STRUCTURE_ERROR)\n    fun `check wrong constructor expression but with ignore opening brace config`() {\n        lintMethod(\n            \"\"\"\n                    |class Person()\n                    |{\n                    |   constructor(id: Int) {\n                    |       println(id)\n                    |   }\n                    |}\n            \"\"\".trimMargin(), rulesConfigList = rulesConfigListIgnoreOpen\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.BRACES_BLOCK_STRUCTURE_ERROR)\n    fun `check lambda with incorrect close brace position`() {\n        lintMethod(\n            \"\"\"\n                    |class Person() {\n                    |   val list = listOf(\"Hello\", \"World\")\n                    |\n                    |   fun foo(){\n                    |       val size = list.map { it.length }\n                    |       size.forEach { println(it) }\n                    |   }\n                    |}\n            \"\"\".trimMargin()\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.BRACES_BLOCK_STRUCTURE_ERROR)\n    fun `check lambdas`() {\n        lintMethod(\n            \"\"\"\n                    |fun foo() {\n                    |   val x = t.map {it -> it.size}\n                    |   val y = q\n                    |          .map { it.treeParent }\n                    |           .filter { it.elementType == CLASS }\n                    |   val y = q\n                    |           .map { it.treeParent }\n                    |           .filter { it.elementType == CLASS &&\n                    |               it.text == \"sdc\" }\n                    |}\n            \"\"\".trimMargin(),\n            DiktatError(9, 33, ruleId, \"${BRACES_BLOCK_STRUCTURE_ERROR.warnText()} no newline before closing brace\", true)\n        )\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/test/kotlin/com/saveourtool/diktat/ruleset/chapter3/BooleanExpressionsRuleFixTest.kt",
    "content": "package com.saveourtool.diktat.ruleset.chapter3\n\nimport com.saveourtool.diktat.ruleset.rules.chapter3.BooleanExpressionsRule\nimport com.saveourtool.diktat.util.FixTestBase\n\nimport generated.WarningNames\nimport org.junit.jupiter.api.Tag\nimport org.junit.jupiter.api.Test\n\nclass BooleanExpressionsRuleFixTest : FixTestBase(\"test/paragraph3/boolean_expressions\", ::BooleanExpressionsRule) {\n    @Test\n    @Tag(WarningNames.COMPLEX_BOOLEAN_EXPRESSION)\n    fun fixBooleanExpressions() {\n        fixAndCompare(\"BooleanExpressionsExpected.kt\", \"BooleanExpressionsTest.kt\")\n    }\n\n    @Test\n    @Tag(WarningNames.COMPLEX_BOOLEAN_EXPRESSION)\n    fun `check distributive law fixing`() {\n        fixAndCompare(\"DistributiveLawExpected.kt\", \"DistributiveLawTest.kt\")\n    }\n\n    @Test\n    @Tag(WarningNames.COMPLEX_BOOLEAN_EXPRESSION)\n    fun `check same expressions`() {\n        fixAndCompare(\"SameExpressionsInConditionExpected.kt\", \"SameExpressionsInConditionTest.kt\")\n    }\n\n    @Test\n    @Tag(WarningNames.COMPLEX_BOOLEAN_EXPRESSION)\n    fun `check substitution works properly`() {\n        fixAndCompare(\"SubstitutionIssueExpected.kt\", \"SubstitutionIssueTest.kt\")\n    }\n\n    @Test\n    @Tag(WarningNames.COMPLEX_BOOLEAN_EXPRESSION)\n    fun `check ordering is persisted`() {\n        fixAndCompare(\"OrderIssueExpected.kt\", \"OrderIssueTest.kt\")\n    }\n\n    @Test\n    @Tag(WarningNames.COMPLEX_BOOLEAN_EXPRESSION)\n    fun `check handling of negative expression`() {\n        fixAndCompare(\"NegativeExpressionExpected.kt\", \"NegativeExpressionTest.kt\")\n    }\n\n    @Test\n    @Tag(WarningNames.COMPLEX_BOOLEAN_EXPRESSION)\n    fun `check expression simplification`() {\n        fixAndCompare(\"ExpressionSimplificationExpected.kt\", \"ExpressionSimplificationTest.kt\")\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/test/kotlin/com/saveourtool/diktat/ruleset/chapter3/BooleanExpressionsRuleWarnTest.kt",
    "content": "package com.saveourtool.diktat.ruleset.chapter3\n\nimport com.saveourtool.diktat.common.config.rules.DIKTAT_RULE_SET_ID\nimport com.saveourtool.diktat.ruleset.constants.Warnings\nimport com.saveourtool.diktat.ruleset.rules.chapter3.BooleanExpressionsRule\nimport com.saveourtool.diktat.ruleset.utils.KotlinParser\nimport com.saveourtool.diktat.util.LintTestBase\n\nimport com.saveourtool.diktat.api.DiktatError\nimport generated.WarningNames\nimport org.junit.jupiter.api.Assertions\nimport org.junit.jupiter.api.Tag\nimport org.junit.jupiter.api.Test\nimport java.io.ByteArrayOutputStream\nimport java.io.PrintStream\n\nclass BooleanExpressionsRuleWarnTest : LintTestBase(::BooleanExpressionsRule) {\n    private val ruleId = \"$DIKTAT_RULE_SET_ID:${BooleanExpressionsRule.NAME_ID}\"\n\n    @Test\n    @Tag(WarningNames.COMPLEX_BOOLEAN_EXPRESSION)\n    fun `check boolean expression`() {\n        lintMethod(\n            \"\"\"\n                    |fun foo() {\n                    |    if (some != null && some != null && some == null) {\n                    |       goo()\n                    |    }\n                    |\n                    |    if (some != null && some == 7) {\n                    |\n                    |    }\n                    |\n                    |    if (a > 3 && b > 3 && a > 3) {\n                    |\n                    |    }\n                    |\n                    |    if (a && a && b > 4) {\n                    |\n                    |    }\n                    |}\n            \"\"\".trimMargin(),\n            DiktatError(2, 9, ruleId, \"${Warnings.COMPLEX_BOOLEAN_EXPRESSION.warnText()} some != null && some != null && some == null\", true),\n            DiktatError(10, 9, ruleId, \"${Warnings.COMPLEX_BOOLEAN_EXPRESSION.warnText()} a > 3 && b > 3 && a > 3\", true),\n            DiktatError(14, 9, ruleId, \"${Warnings.COMPLEX_BOOLEAN_EXPRESSION.warnText()} a && a && b > 4\", true)\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.COMPLEX_BOOLEAN_EXPRESSION)\n    fun `check laws#1`() {\n        lintMethod(\n            \"\"\"\n                    |fun foo() {\n                    |    if (some != null && (some != null || a > 5)) {\n                    |\n                    |    }\n                    |\n                    |    if (a > 5 || (a > 5 && b > 6)) {\n                    |\n                    |    }\n                    |\n                    |    if (!!(a > 5 && q > 6)) {\n                    |\n                    |    }\n                    |\n                    |    if (a > 5 && false) {\n                    |\n                    |    }\n                    |\n                    |    if (a > 5 || (!(a > 5) && b > 5)) {\n                    |\n                    |    }\n                    |}\n            \"\"\".trimMargin(),\n            DiktatError(2, 9, ruleId, \"${Warnings.COMPLEX_BOOLEAN_EXPRESSION.warnText()} some != null && (some != null || a > 5)\", true),\n            DiktatError(6, 9, ruleId, \"${Warnings.COMPLEX_BOOLEAN_EXPRESSION.warnText()} a > 5 || (a > 5 && b > 6)\", true),\n            DiktatError(10, 9, ruleId, \"${Warnings.COMPLEX_BOOLEAN_EXPRESSION.warnText()} !!(a > 5 && q > 6)\", true),\n            DiktatError(14, 9, ruleId, \"${Warnings.COMPLEX_BOOLEAN_EXPRESSION.warnText()} a > 5 && false\", true),\n            DiktatError(18, 9, ruleId, \"${Warnings.COMPLEX_BOOLEAN_EXPRESSION.warnText()} a > 5 || (!(a > 5) && b > 5)\", true)\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.COMPLEX_BOOLEAN_EXPRESSION)\n    fun `check distributive laws`() {\n        lintMethod(\n            \"\"\"\n                    |fun foo() {\n                    |    if ((a > 5 || b > 5) && (a > 5 || c > 5)) {\n                    |\n                    |    }\n                    |\n                    |    if (a > 5 && b > 5 || a > 5 && c > 5) {\n                    |\n                    |    }\n                    |}\n            \"\"\".trimMargin(),\n            DiktatError(2, 9, ruleId, \"${Warnings.COMPLEX_BOOLEAN_EXPRESSION.warnText()} (a > 5 || b > 5) && (a > 5 || c > 5)\", true),\n            DiktatError(6, 9, ruleId, \"${Warnings.COMPLEX_BOOLEAN_EXPRESSION.warnText()} a > 5 && b > 5 || a > 5 && c > 5\", true)\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.COMPLEX_BOOLEAN_EXPRESSION)\n    fun `check distributive laws #2`() {\n        lintMethod(\n            \"\"\"\n                    |fun foo() {\n                    |    if ((a > 5 || b > 5) && (a > 5 || c > 5) && (a > 5 || d > 5)) {\n                    |\n                    |    }\n                    |\n                    |    if (a > 5 && b > 5 || a > 5 && c > 5 || a > 5 || d > 5) {\n                    |\n                    |    }\n                    |}\n            \"\"\".trimMargin(),\n            DiktatError(2, 9, ruleId, \"${Warnings.COMPLEX_BOOLEAN_EXPRESSION.warnText()} (a > 5 || b > 5) && (a > 5 || c > 5) && (a > 5 || d > 5)\", true),\n            DiktatError(6, 9, ruleId, \"${Warnings.COMPLEX_BOOLEAN_EXPRESSION.warnText()} a > 5 && b > 5 || a > 5 && c > 5 || a > 5 || d > 5\", true)\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.COMPLEX_BOOLEAN_EXPRESSION)\n    fun `should not trigger on method calls`() {\n        lintMethod(\n            \"\"\"\n                    |fun foo() {\n                    |    if (a.and(b)) {\n                    |\n                    |    }\n                    |}\n            \"\"\".trimMargin()\n        )\n    }\n\n    @Test\n    fun `test makeCorrectExpressionString method #1`() {\n        checkExpressionFormatter(\"a > 5 && b < 6\", \"(A & B)\", 2)\n    }\n\n    @Test\n    fun `test makeCorrectExpressionString method #2`() {\n        checkExpressionFormatter(\"a > 5 && b < 6 && c > 7 || a > 5\", \"(A & B & C | A)\", 3)\n    }\n\n    @Test\n    fun `test makeCorrectExpressionString method #3`() {\n        checkExpressionFormatter(\"a > 5 && b < 6 && (c > 3 || b < 6) && a > 5\", \"(A & B & (C | B) & A)\", 3)\n    }\n\n    @Test\n    fun `test makeCorrectExpressionString method #4`() {\n        checkExpressionFormatter(\"a > 5 && b < 6 && (c > 3 || b < 6) && a > 666\", \"(A & B & (C | B) & D)\", 4)\n    }\n\n    @Test\n    fun `test makeCorrectExpressionString method #5 - should not convert single expressions`() {\n        checkExpressionFormatter(\"a.and(b)\", \"(a.and(b))\", 0)\n    }\n\n    @Test\n    fun `test makeCorrectExpressionString method #6 - should not convert single expressions`() {\n        checkExpressionFormatter(\"x.isFoo()\", \"(x.isFoo())\", 0)\n    }\n\n    @Test\n    fun `test makeCorrectExpressionString method #7`() {\n        checkExpressionFormatter(\"x.isFoo() && true\", \"(A & true)\", 1)\n    }\n\n    @Test\n    fun `test makeCorrectExpressionString method #8`() {\n        checkExpressionFormatter(\n            \"a > 5 && b > 6 || c > 7 && a > 5\",\n            \"(A & B | C & A)\",\n            3\n        )\n    }\n\n    @Test\n    fun `test makeCorrectExpressionString method #9 - should not account for boolean operators in nested lambdas`() {\n        checkExpressionFormatter(\n            \"\"\"\n                nextNode != null && nextNode.findChildByType(CALL_EXPRESSION)?.text?.let {\n                    it == \"trimIndent()\" || it == \"trimMargin()\"\n                } == true\n            \"\"\".trimIndent(),\n            \"(A & B)\",\n            2\n        )\n    }\n\n    @Test\n    fun `test makeCorrectExpressionString method #10 - single variable in condition`() {\n        checkExpressionFormatter(\n            \"::testContainerId.isInitialized\",\n            \"(::testContainerId.isInitialized)\",\n            0\n        )\n    }\n\n    @Test\n    fun `test makeCorrectExpressionString method #11 - variable in condition and binary expression`() {\n        checkExpressionFormatter(\n            \"::testContainerId.isInitialized || a > 2\",\n            \"(B | A)\",\n            2\n        )\n    }\n\n    @Test\n    fun `test makeCorrectExpressionString method - comment should be removed`() {\n        checkExpressionFormatter(\n            \"\"\"\n                foo && bar &&\n                // FixMe: isLetterOrDigit is not supported in Kotlin 1.4, but 1.5 is not compiling right now\n                setOf('_', '-', '.', '\"', '\\'').baz() && ch.isLetterOrDigit()\n            \"\"\".trimIndent(),\n            \"(C & D &  B & A)\",\n            4\n        )\n    }\n\n    @Test\n    @Suppress(\"TOO_LONG_FUNCTION\", \"LongMethod\")\n    fun `regression - should not log ANTLR errors when parsing is not required`() {\n        val stream = ByteArrayOutputStream()\n        System.setErr(PrintStream(stream))\n        lintMethod(\n            \"\"\"\n                fun foo() {\n                    // nested boolean expressions in lambdas\n                    if (currentProperty.nextSibling { it.elementType == PROPERTY } == nextProperty) {}\n\n                    if (rightSide != null && leftSide != null &&\n                        rightSide.size == leftSide.size &&\n                        rightSide.zip(leftSide).all { (first, second) -> first.text == second.text }) {}\n\n                    // nested lambda with if-else\n                    if (currentProperty.nextSibling { if (it.elementType == PROPERTY) true else false } == nextProperty) {}\n\n                    // nested boolean expressions in lambdas with multi-line expressions\n                    if (node.elementType == TYPE_REFERENCE && node\n                        .parents()\n                        .map { it.elementType }\n                        .none { it == SUPER_TYPE_LIST || it == TYPEALIAS }) {}\n\n                    // binary expression with boolean literal\n                    if (result?.flag == true) {}\n\n                    if (leftOffset + binaryText.length > wrongBinaryExpression.maximumLineLength && index != 0) {}\n\n                    // with in and !in\n                    if (!isImportOrPackage && previousNonWhiteSpaceNode in acc.last()) {}\n                    if (node.elementType == LABEL_QUALIFIER && node.text !in labels && node.treeParent.elementType in stopWords) {}\n\n                    if ((node.treeNext.elementType == RBRACE) xor (node.treePrev.elementType == LBRACE)) {}\n\n                    if (listOfNodesBeforeNestedIf.any { it.elementType !in allowedTypes } ||\n                        listOfNodesAfterNestedIf.any { it.elementType !in allowedTypes }) {\n                            return null\n                    }\n                    if ((parentNode.psi as KtIfExpression).`else` != null ||\n                        (nestedIfNode.psi as KtIfExpression).`else` != null) {}\n                    if (listOfWarnings.add(currNode.startOffset to currNode)) {}\n                }\n            \"\"\".trimIndent()\n        )\n        System.setErr(System.err)\n        val stderr = stream.toString()\n        Assertions.assertTrue(stderr.isEmpty()) {\n            \"stderr should be empty, but got the following:${System.lineSeparator()}$stderr\"\n        }\n    }\n\n    private fun checkExpressionFormatter(\n        expression: String,\n        expectedRepresentation: String,\n        expectedMapSize: Int\n    ) {\n        val stream = ByteArrayOutputStream()\n        System.setErr(PrintStream(stream))\n        val node = KotlinParser().createNode(expression)\n        val rule = BooleanExpressionsRule(emptyList())\n        val map: BooleanExpressionsRule.ExpressionsReplacement = rule.ExpressionsReplacement()\n        val result = rule.formatBooleanExpressionAsString(node, map)\n        Assertions.assertEquals(expectedRepresentation, result)\n        Assertions.assertEquals(expectedMapSize, map.size())\n        System.setErr(System.err)\n        val stderr = stream.toString()\n        Assertions.assertTrue(stderr.isEmpty()) {\n            \"stderr should be empty, but got the following:${System.lineSeparator()}$stderr\"\n        }\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/test/kotlin/com/saveourtool/diktat/ruleset/chapter3/BracesRuleFixTest.kt",
    "content": "package com.saveourtool.diktat.ruleset.chapter3\n\nimport com.saveourtool.diktat.ruleset.rules.chapter3.BracesInConditionalsAndLoopsRule\nimport com.saveourtool.diktat.util.FixTestBase\n\nimport generated.WarningNames\nimport org.junit.jupiter.api.Tag\nimport org.junit.jupiter.api.Test\n\nclass BracesRuleFixTest : FixTestBase(\"test/paragraph3/braces\", ::BracesInConditionalsAndLoopsRule) {\n    @Test\n    @Tag(WarningNames.NO_BRACES_IN_CONDITIONALS_AND_LOOPS)\n    fun `should add braces to if-else statements - 1`() {\n        fixAndCompare(\"IfElseBraces1Expected.kt\", \"IfElseBraces1Test.kt\")\n    }\n\n    @Test\n    @Tag(WarningNames.NO_BRACES_IN_CONDITIONALS_AND_LOOPS)\n    fun `should add braces to loops with single statement`() {\n        fixAndCompare(\"LoopsBracesExpected.kt\", \"LoopsBracesTest.kt\")\n    }\n\n    @Test\n    @Tag(WarningNames.NO_BRACES_IN_CONDITIONALS_AND_LOOPS)\n    fun `should add braces to if-else statements inside scope functions`() {\n        fixAndCompare(\"IfElseBracesInsideScopeFunctionsExpected.kt\", \"IfElseBracesInsideScopeFunctionsTest.kt\")\n    }\n\n    @Test\n    @Tag(WarningNames.NO_BRACES_IN_CONDITIONALS_AND_LOOPS)\n    fun `should add braces to loops inside scope functions`() {\n        fixAndCompare(\"LoopsBracesInsideScopeFunctionsExpected.kt\", \"LoopsBracesInsideScopeFunctionsTest.kt\")\n    }\n\n    @Test\n    @Tag(WarningNames.NO_BRACES_IN_CONDITIONALS_AND_LOOPS)\n    fun `should add braces to do-while loops with empty body`() {\n        fixAndCompare(\"DoWhileBracesExpected.kt\", \"DoWhileBracesTest.kt\")\n    }\n\n    @Test\n    @Tag(WarningNames.NO_BRACES_IN_CONDITIONALS_AND_LOOPS)\n    fun `should remove braces from single-line when branches`() {\n        fixAndCompare(\"WhenBranchesExpected.kt\", \"WhenBranchesTest.kt\")\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/test/kotlin/com/saveourtool/diktat/ruleset/chapter3/BracesRuleWarnTest.kt",
    "content": "package com.saveourtool.diktat.ruleset.chapter3\n\nimport com.saveourtool.diktat.common.config.rules.DIKTAT_RULE_SET_ID\nimport com.saveourtool.diktat.ruleset.constants.Warnings.NO_BRACES_IN_CONDITIONALS_AND_LOOPS\nimport com.saveourtool.diktat.ruleset.rules.chapter3.BracesInConditionalsAndLoopsRule\nimport com.saveourtool.diktat.util.LintTestBase\n\nimport com.saveourtool.diktat.api.DiktatError\nimport generated.WarningNames\nimport org.junit.jupiter.api.Tag\nimport org.junit.jupiter.api.Test\n\nclass BracesRuleWarnTest : LintTestBase(::BracesInConditionalsAndLoopsRule) {\n    private val ruleId = \"$DIKTAT_RULE_SET_ID:${BracesInConditionalsAndLoopsRule.NAME_ID}\"\n\n    @Test\n    @Tag(WarningNames.NO_BRACES_IN_CONDITIONALS_AND_LOOPS)\n    fun `should check braces in if statement without else branch - positive example`() {\n        lintMethod(\n            \"\"\"\n                    |fun foo() {\n                    |    if (x > 0) {\n                    |        bar()\n                    |    }\n                    |}\n            \"\"\".trimMargin()\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.NO_BRACES_IN_CONDITIONALS_AND_LOOPS)\n    fun `should check braces in if statement without else branch`() {\n        lintMethod(\n            \"\"\"\n                    |fun foo() {\n                    |    if (x > 0)\n                    |        bar()\n                    |\n                    |    if (y < 0) baz()\n                    |}\n            \"\"\".trimMargin(),\n            DiktatError(2, 5, ruleId, \"${NO_BRACES_IN_CONDITIONALS_AND_LOOPS.warnText()} IF\", true),\n            DiktatError(5, 5, ruleId, \"${NO_BRACES_IN_CONDITIONALS_AND_LOOPS.warnText()} IF\", true)\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.NO_BRACES_IN_CONDITIONALS_AND_LOOPS)\n    fun `should check braces in if statements - positive example`() {\n        lintMethod(\n            \"\"\"\n                    |fun foo() {\n                    |    if (x > 0) {\n                    |        bar()\n                    |    } else if (x == 0) {\n                    |        bzz()\n                    |    } else {\n                    |        baz()\n                    |    }\n                    |}\n            \"\"\".trimMargin()\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.NO_BRACES_IN_CONDITIONALS_AND_LOOPS)\n    fun `should check braces in if statements`() {\n        lintMethod(\n            \"\"\"\n                    |fun foo() {\n                    |    if (x > 0)\n                    |        bar()\n                    |    else if (x == 0)\n                    |        bzz()\n                    |    else\n                    |        baz()\n                    |}\n            \"\"\".trimMargin(),\n            DiktatError(2, 5, ruleId, \"${NO_BRACES_IN_CONDITIONALS_AND_LOOPS.warnText()} IF\", true),\n            DiktatError(4, 10, ruleId, \"${NO_BRACES_IN_CONDITIONALS_AND_LOOPS.warnText()} IF\", true),\n            DiktatError(6, 5, ruleId, \"${NO_BRACES_IN_CONDITIONALS_AND_LOOPS.warnText()} ELSE\", true)\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.NO_BRACES_IN_CONDITIONALS_AND_LOOPS)\n    fun `should check braces in if statements - exception for single line if`() {\n        lintMethod(\n            \"\"\"\n                    |fun foo() {\n                    |    if (x > 0) bar() else baz()\n                    |}\n            \"\"\".trimMargin()\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.NO_BRACES_IN_CONDITIONALS_AND_LOOPS)\n    fun `should check braces in if statements - exception for let`() {\n        lintMethod(\n            \"\"\"\n            |fun foo() {\n            |    if (a) {\n            |        bar()\n            |    } else b?.let {\n            |        baz()\n            |    }\n            |        ?: run {\n            |            qux()\n            |        }\n            |}\n            \"\"\".trimMargin()\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.NO_BRACES_IN_CONDITIONALS_AND_LOOPS)\n    fun `should check braces in if statements - exception for let 2`() {\n        lintMethod(\n            \"\"\"\n            |fun foo() {\n            |    if (a) {\n            |        bar()\n            |    } else b?.let {\n            |        baz()\n            |    }\n            |}\n            \"\"\".trimMargin()\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.NO_BRACES_IN_CONDITIONALS_AND_LOOPS)\n    fun `should check braces in if statements - exception for run`() {\n        lintMethod(\n            \"\"\"\n            |fun foo() {\n            |    if (a) {\n            |        bar()\n            |    } else b!!.run {\n            |        baz()\n            |    }\n            |}\n            \"\"\".trimMargin()\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.NO_BRACES_IN_CONDITIONALS_AND_LOOPS)\n    fun `should check braces in if statements - exception for apply`() {\n        lintMethod(\n            \"\"\"\n            |fun foo() {\n            |    if (a) {\n            |        bar()\n            |    } else b.apply {\n            |        baz()\n            |    }\n            |}\n            \"\"\".trimMargin()\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.NO_BRACES_IN_CONDITIONALS_AND_LOOPS)\n    fun `should check braces in if statements, apply exists, but braces are needed`() {\n        lintMethod(\n            \"\"\"\n            |fun foo() {\n            |    if (a) {\n            |        bar()\n            |    } else baz(b.apply { id = 5 })\n            |}\n            \"\"\".trimMargin(),\n            DiktatError(4, 7, ruleId, \"${NO_BRACES_IN_CONDITIONALS_AND_LOOPS.warnText()} ELSE\", true)\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.NO_BRACES_IN_CONDITIONALS_AND_LOOPS)\n    fun `should check braces in if statements, apply exists, but braces are needed 2`() {\n        lintMethod(\n            \"\"\"\n            |fun foo() {\n            |    if (a) {\n            |        bar()\n            |    } else\n            |        c.baz(b.apply {id = 5})\n            |}\n            \"\"\".trimMargin(),\n            DiktatError(4, 7, ruleId, \"${NO_BRACES_IN_CONDITIONALS_AND_LOOPS.warnText()} ELSE\", true)\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.NO_BRACES_IN_CONDITIONALS_AND_LOOPS)\n    fun `should correctly detect single line if`() {\n        lintMethod(\n            \"\"\"\n                    |fun foo() {\n                    |    if (x > 0) {\n                    |        bar()\n                    |    } else if (x == 0) bar() else baz()\n                    |}\n            \"\"\".trimMargin(),\n            DiktatError(4, 12, ruleId, \"${NO_BRACES_IN_CONDITIONALS_AND_LOOPS.warnText()} IF\", true),\n            DiktatError(4, 30, ruleId, \"${NO_BRACES_IN_CONDITIONALS_AND_LOOPS.warnText()} ELSE\", true)\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.NO_BRACES_IN_CONDITIONALS_AND_LOOPS)\n    fun `should check braces in if statements - empty body`() {\n        lintMethod(\n            \"\"\"\n                    |fun foo() {\n                    |    if (x > 0)\n                    |    else if (x == 0)\n                    |    else foo()\n                    |}\n            \"\"\".trimMargin(),\n            DiktatError(2, 5, ruleId, \"${NO_BRACES_IN_CONDITIONALS_AND_LOOPS.warnText()} IF\", true),\n            DiktatError(3, 10, ruleId, \"${NO_BRACES_IN_CONDITIONALS_AND_LOOPS.warnText()} IF\", true),\n            DiktatError(4, 5, ruleId, \"${NO_BRACES_IN_CONDITIONALS_AND_LOOPS.warnText()} ELSE\", true)\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.NO_BRACES_IN_CONDITIONALS_AND_LOOPS)\n    fun `should warn if single line branches in when are used with braces`() {\n        lintMethod(\n            \"\"\"\n                    |fun foo() {\n                    |    when (x) {\n                    |        OPTION_1 -> {\n                    |            foo()\n                    |            println()\n                    |        }\n                    |        OPTION_2 -> { bar() }\n                    |        OPTION_3 -> {\n                    |            baz()\n                    |        }\n                    |        OPTION_4 -> {\n                    |            // description\n                    |            bzz()\n                    |        }\n                    |    }\n                    |}\n            \"\"\".trimMargin(),\n            DiktatError(7, 21, ruleId, \"${NO_BRACES_IN_CONDITIONALS_AND_LOOPS.warnText()} WHEN\", true),\n            DiktatError(8, 21, ruleId, \"${NO_BRACES_IN_CONDITIONALS_AND_LOOPS.warnText()} WHEN\", true)\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.NO_BRACES_IN_CONDITIONALS_AND_LOOPS)\n    fun `for loops should have braces - positive example`() {\n        lintMethod(\n            \"\"\"\n                    |fun foo() {\n                    |    for (i in 1..100) {\n                    |        println(i)\n                    |    }\n                    |}\n            \"\"\".trimMargin()\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.NO_BRACES_IN_CONDITIONALS_AND_LOOPS)\n    fun `for loops should have braces`() {\n        lintMethod(\n            \"\"\"\n                    |fun foo() {\n                    |    for (i in 1..100)\n                    |        println(i)\n                    |}\n            \"\"\".trimMargin(),\n            DiktatError(2, 5, ruleId, \"${NO_BRACES_IN_CONDITIONALS_AND_LOOPS.warnText()} FOR\", true)\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.NO_BRACES_IN_CONDITIONALS_AND_LOOPS)\n    fun `while loops should have braces - positive example`() {\n        lintMethod(\n            \"\"\"\n                    |fun foo() {\n                    |    while (condition) {\n                    |        println(\"\")\n                    |    }\n                    |}\n            \"\"\".trimMargin()\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.NO_BRACES_IN_CONDITIONALS_AND_LOOPS)\n    fun `while loops should have braces`() {\n        lintMethod(\n            \"\"\"\n                    |fun foo() {\n                    |    while (condition)\n                    |        println(\"\")\n                    |}\n            \"\"\".trimMargin(),\n            DiktatError(2, 5, ruleId, \"${NO_BRACES_IN_CONDITIONALS_AND_LOOPS.warnText()} WHILE\", true)\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.NO_BRACES_IN_CONDITIONALS_AND_LOOPS)\n    fun `do-while loops should have braces - positive example`() {\n        lintMethod(\n            \"\"\"\n                    |fun foo() {\n                    |    do {\n                    |        println(\"\")\n                    |    } while (condition)\n                    |}\n            \"\"\".trimMargin()\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.NO_BRACES_IN_CONDITIONALS_AND_LOOPS)\n    fun `do-while loops should have braces`() {\n        lintMethod(\n            \"\"\"\n                    |fun foo() {\n                    |    do println(i) while (condition)\n                    |}\n            \"\"\".trimMargin(),\n            DiktatError(2, 5, ruleId, \"${NO_BRACES_IN_CONDITIONALS_AND_LOOPS.warnText()} DO_WHILE\", true)\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.NO_BRACES_IN_CONDITIONALS_AND_LOOPS)\n    fun `do-while loops should have braces - empty body`() {\n        lintMethod(\n            \"\"\"\n                    |fun foo() {\n                    |    do while (condition)\n                    |}\n            \"\"\".trimMargin(),\n            DiktatError(2, 5, ruleId, \"${NO_BRACES_IN_CONDITIONALS_AND_LOOPS.warnText()} DO_WHILE\", true)\n        )\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/test/kotlin/com/saveourtool/diktat/ruleset/chapter3/ClassLikeStructuresOrderFixTest.kt",
    "content": "package com.saveourtool.diktat.ruleset.chapter3\n\nimport com.saveourtool.diktat.ruleset.rules.chapter3.ClassLikeStructuresOrderRule\nimport com.saveourtool.diktat.util.FixTestBase\n\nimport generated.WarningNames\nimport org.junit.jupiter.api.Tag\nimport org.junit.jupiter.api.Tags\nimport org.junit.jupiter.api.Test\n\nclass ClassLikeStructuresOrderFixTest : FixTestBase(\"test/paragraph3/file_structure\", ::ClassLikeStructuresOrderRule) {\n    @Test\n    @Tags(Tag(WarningNames.BLANK_LINE_BETWEEN_PROPERTIES), Tag(WarningNames.WRONG_ORDER_IN_CLASS_LIKE_STRUCTURES))\n    fun `should fix order and newlines between properties`() {\n        fixAndCompare(\"DeclarationsInClassOrderExpected.kt\", \"DeclarationsInClassOrderTest.kt\")\n    }\n\n    @Test\n    @Tags(Tag(WarningNames.BLANK_LINE_BETWEEN_PROPERTIES), Tag(WarningNames.WRONG_ORDER_IN_CLASS_LIKE_STRUCTURES))\n    fun `should fix order and newlines with comment`() {\n        fixAndCompare(\"OrderWithCommentExpected.kt\", \"OrderWithCommentTest.kt\")\n    }\n\n    @Test\n    @Tags(Tag(WarningNames.WRONG_ORDER_IN_CLASS_LIKE_STRUCTURES))\n    fun `regression - should not remove enum members`() {\n        fixAndCompare(\"OrderWithEnumsExpected.kt\", \"OrderWithEnumsTest.kt\")\n    }\n\n    @Test\n    @Tags(Tag(WarningNames.WRONG_ORDER_IN_CLASS_LIKE_STRUCTURES))\n    fun `regression - should not move loggers that depend on other variables from scope`() {\n        fixAndCompare(\"LoggerOrderExpected.kt\", \"LoggerOrderTest.kt\")\n    }\n\n    @Test\n    @Tag(WarningNames.BLANK_LINE_BETWEEN_PROPERTIES)\n    fun `should add new line before the comment`() {\n        fixAndCompare(\"CompanionObjectWithCommentExpected.kt\", \"CompanionObjectWithCommentTest.kt\")\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/test/kotlin/com/saveourtool/diktat/ruleset/chapter3/ClassLikeStructuresOrderRuleWarnTest.kt",
    "content": "package com.saveourtool.diktat.ruleset.chapter3\n\nimport com.saveourtool.diktat.common.config.rules.DIKTAT_RULE_SET_ID\nimport com.saveourtool.diktat.ruleset.constants.Warnings.BLANK_LINE_BETWEEN_PROPERTIES\nimport com.saveourtool.diktat.ruleset.constants.Warnings.WRONG_ORDER_IN_CLASS_LIKE_STRUCTURES\nimport com.saveourtool.diktat.ruleset.rules.chapter3.ClassLikeStructuresOrderRule\nimport com.saveourtool.diktat.util.LintTestBase\n\nimport com.saveourtool.diktat.api.DiktatError\nimport com.saveourtool.diktat.test.framework.util.describe\nimport generated.WarningNames\nimport org.assertj.core.api.Assertions.assertThat\nimport org.intellij.lang.annotations.Language\nimport org.junit.jupiter.api.Tag\nimport org.junit.jupiter.api.Test\n\nclass ClassLikeStructuresOrderRuleWarnTest : LintTestBase(::ClassLikeStructuresOrderRule) {\n    private val ruleId = \"$DIKTAT_RULE_SET_ID:${ClassLikeStructuresOrderRule.NAME_ID}\"\n\n    // ===== order of declarations =====\n\n    @Language(\"kotlin\")\n    private fun codeTemplate(keyword: String) = \"\"\"\n                    |$keyword Example {\n                    |    private val log = LoggerFactory.getLogger(Example.javaClass)\n                    |    private val FOO = 42\n                    |    private lateinit var lateFoo: Int\n                    |    init {\n                    |        bar()\n                    |    }\n                    |    constructor(baz: Int)\n                    |    fun foo() {\n                    |        val nested = Nested()\n                    |    }\n                    |    class Nested {\n                    |        val nestedFoo = 43\n                    |    }\n                    |    companion object {\n                    |        private const val ZERO = 0\n                    |        private var i = 0\n                    |    }\n                    |    class UnusedNested { }\n                    |}\n                \"\"\".trimMargin()\n\n    @Test\n    @Tag(WarningNames.WRONG_ORDER_IN_CLASS_LIKE_STRUCTURES)\n    fun `should check order of declarations in classes - positive example`() {\n        listOf(\"class\", \"interface\", \"object\").forEach { keyword ->\n            lintMethod(codeTemplate(keyword))\n        }\n    }\n\n    @Test\n    @Tag(WarningNames.WRONG_ORDER_IN_CLASS_LIKE_STRUCTURES)\n    fun `should warn if loggers are not on top`() {\n        lintMethod(\n            \"\"\"\n                    |class Example {\n                    |    private val FOO = 42\n                    |    private val log = LoggerFactory.getLogger(Example.javaClass)\n                    |}\n            \"\"\".trimMargin(),\n            DiktatError(2, 5, ruleId, \"${WRONG_ORDER_IN_CLASS_LIKE_STRUCTURES.warnText()} PROPERTY: FOO\", true),\n            DiktatError(3, 5, ruleId, \"${WRONG_ORDER_IN_CLASS_LIKE_STRUCTURES.warnText()} PROPERTY: log\", true)\n        )\n    }\n\n    // ===== comments on properties ======\n\n    @Test\n    @Tag(WarningNames.BLANK_LINE_BETWEEN_PROPERTIES)\n    fun `comments and KDocs on properties should be prepended by newline - positive example`() {\n        lintMethod(\n            \"\"\"\n                    |class Example {\n                    |    // logger property\n                    |    private val log = LoggerFactory.getLogger(Example.javaClass)\n                    |    private val FOO = 42\n                    |\n                    |    // another property\n                    |    private val BAR = 43\n                    |\n                    |    @Annotated\n                    |    private val qux = 43\n                    |\n                    |    // annotated property\n                    |    @Annotated\n                    |    private val quux = 43\n                    |\n                    |    /**\n                    |     * Yet another property.\n                    |     */\n                    |    private val BAZ = 44\n                    |    @Annotated private lateinit var lateFoo: Int\n                    |}\n            \"\"\".trimMargin())\n    }\n\n    @Test\n    @Tag(WarningNames.BLANK_LINE_BETWEEN_PROPERTIES)\n    fun `should warn if comments and KDocs on properties are not prepended by newline`() {\n        lintMethod(\n            \"\"\"\n                    |class Example {\n                    |    private val log = LoggerFactory.getLogger(Example.javaClass)\n                    |    private val FOO = 42\n                    |    // another property\n                    |    private val BAR = 43\n                    |    @Anno\n                    |    private val qux = 43\n                    |    // annotated property\n                    |    @Anno\n                    |    private val quux = 43\n                    |    /**\n                    |     * Yet another property.\n                    |     */\n                    |    private val BAZ = 44\n                    |    private lateinit var lateFoo: Int\n                    |}\n            \"\"\".trimMargin(),\n            DiktatError(4, 5, ruleId, \"${BLANK_LINE_BETWEEN_PROPERTIES.warnText()} BAR\", true),\n            DiktatError(6, 5, ruleId, \"${BLANK_LINE_BETWEEN_PROPERTIES.warnText()} qux\", true),\n            DiktatError(8, 5, ruleId, \"${BLANK_LINE_BETWEEN_PROPERTIES.warnText()} quux\", true),\n            DiktatError(11, 5, ruleId, \"${BLANK_LINE_BETWEEN_PROPERTIES.warnText()} BAZ\", true)\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.BLANK_LINE_BETWEEN_PROPERTIES)\n    fun `regression - should check only class-level and top-level properties`() {\n        lintMethod(\n            \"\"\"class Example {\n                    |    fun foo() {\n                    |        val bar = 0\n                    |\n                    |        val baz = 1\n                    |    }\n                    |\n                    |    class Nested {\n                    |        val bar = 0\n                    |        val baz = 1\n                    |    }\n                    |}\n            \"\"\".trimMargin()\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.BLANK_LINE_BETWEEN_PROPERTIES)\n    fun `a single-line comment after annotation`() {\n        lintMethod(\n            \"\"\"class Example {\n                    |   private val val0 = Regex(\"\"${'\"'}\\d+\"\"${'\"'})\n                    |\n                    |    @Deprecated(\"Deprecation message\") // Trailing comment\n                    |    private val val2 = \"\"\n                    |}\n            \"\"\".trimMargin()\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.BLANK_LINE_BETWEEN_PROPERTIES)\n    fun `should allow blank lines around properties with custom getters and setters - positive example`() {\n        lintMethod(\n            \"\"\"\n                    |class Example {\n                    |    private val foo\n                    |        get() = 0\n                    |\n                    |    private var backing = 0\n                    |\n                    |    var bar\n                    |        get() = backing\n                    |        set(value) { backing = value }\n                    |}\n            \"\"\".trimMargin()\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.BLANK_LINE_BETWEEN_PROPERTIES)\n    fun `should allow blank lines around properties with custom getters and setters - positive example without blank lines`() {\n        lintMethod(\n            \"\"\"\n                    |class Example {\n                    |    private val foo\n                    |        get() = 0\n                    |    private var backing = 0\n                    |    var bar\n                    |        get() = backing\n                    |        set(value) { backing = value }\n                    |}\n            \"\"\".trimMargin()\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.BLANK_LINE_BETWEEN_PROPERTIES)\n    fun `should not trigger on EOL comment on the same line with property`() {\n        lintMethod(\n            \"\"\"\n                    |class ActiveBinsMetric(meterRegistry: MeterRegistry, private val binRepository: BinRepository) {\n                    |    companion object {\n                    |        private const val EGG_7_9_BUCKET_LABEL = \"7-9\"\n                    |        private const val DELAY = 15000L  // 15s\n                    |    }\n                    |}\n            \"\"\".trimMargin()\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.WRONG_ORDER_IN_CLASS_LIKE_STRUCTURES)\n    fun `should warn if order is incorrect and property with comment`() {\n        lintMethod(\n            \"\"\"\n                    class Example {\n                        companion object {\n                            val b = \"q\"\n\n                            // this\n                            private const val a = 3\n                        }\n                    }\n            \"\"\".trimMargin(),\n            DiktatError(3, 29, ruleId, \"${WRONG_ORDER_IN_CLASS_LIKE_STRUCTURES.warnText()} PROPERTY: b\", true),\n            DiktatError(5, 29, ruleId, \"${WRONG_ORDER_IN_CLASS_LIKE_STRUCTURES.warnText()} PROPERTY: a\", true)\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.WRONG_ORDER_IN_CLASS_LIKE_STRUCTURES)\n    fun `should correctly check class elements order in enum classes`() {\n        lintMethod(\n            \"\"\"\n                enum class Enum {\n                    FOO,\n                    BAR,\n                    ;\n\n                    fun f() {}\n                    companion object\n                }\n            \"\"\".trimMargin()\n        )\n    }\n\n    /**\n     * An exception to the \"loggers on top\" rule.\n     *\n     * See [#1516](https://github.com/saveourtool/diktat/issues/1516).\n     */\n    @Test\n    @Tag(WarningNames.WRONG_ORDER_IN_CLASS_LIKE_STRUCTURES)\n    fun `logger-like const property should not be reordered`() {\n        val code = \"\"\"\n            |object C {\n            |    private const val A = \"value\"\n            |\n            |    // Not a logger\n            |    private const val LOG = \"value\"\n            |}\n        \"\"\".trimMargin()\n\n        val actualErrors = lintResult(code)\n        assertThat(actualErrors)\n            .describedAs(\"lint result for ${code.describe()}\")\n            .isEmpty()\n    }\n\n    /**\n     * An exception to the \"loggers on top\" rule.\n     *\n     * See [#1516](https://github.com/saveourtool/diktat/issues/1516).\n     */\n    @Test\n    @Tag(WarningNames.WRONG_ORDER_IN_CLASS_LIKE_STRUCTURES)\n    fun `logger-like lateinit property should not be reordered`() {\n        val code = \"\"\"\n            |object C {\n            |    private lateinit val A\n            |    private lateinit val LOG // Not a logger\n            |}\n        \"\"\".trimMargin()\n\n        val actualErrors = lintResult(code)\n        assertThat(actualErrors)\n            .describedAs(\"lint result for ${code.describe()}\")\n            .isEmpty()\n    }\n\n    /**\n     * An exception to the \"loggers on top\" rule.\n     *\n     * See [#1516](https://github.com/saveourtool/diktat/issues/1516).\n     */\n    @Test\n    @Tag(WarningNames.WRONG_ORDER_IN_CLASS_LIKE_STRUCTURES)\n    fun `property with a name containing 'log' is not a logger`() {\n        val code = \"\"\"\n            |object C {\n            |    private val a = System.getProperty(\"os.name\")\n            |    private val loginName = LoggerFactory.getLogger({}.javaClass)\n            |}\n        \"\"\".trimMargin()\n\n        val actualErrors = lintResult(code)\n        assertThat(actualErrors)\n            .describedAs(\"lint result for ${code.describe()}\")\n            .isEmpty()\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/test/kotlin/com/saveourtool/diktat/ruleset/chapter3/CollapseIfStatementsRuleFixTest.kt",
    "content": "package com.saveourtool.diktat.ruleset.chapter3\n\nimport com.saveourtool.diktat.common.config.rules.RulesConfig\nimport com.saveourtool.diktat.ruleset.constants.Warnings\nimport com.saveourtool.diktat.ruleset.rules.chapter3.CollapseIfStatementsRule\nimport com.saveourtool.diktat.util.FixTestBase\n\nimport generated.WarningNames\nimport org.junit.jupiter.api.Tag\nimport org.junit.jupiter.api.Test\n\nclass CollapseIfStatementsRuleFixTest : FixTestBase(\n    \"test/paragraph3/collapse_if\",\n    ::CollapseIfStatementsRule,\n    listOf(\n        RulesConfig(Warnings.COLLAPSE_IF_STATEMENTS.name, true, emptyMap())\n    )\n) {\n    @Test\n    @Tag(WarningNames.COLLAPSE_IF_STATEMENTS)\n    fun `collapse if`() {\n        fixAndCompare(\"CollapseIfStatementsExpected.kt\", \"CollapseIfStatementsTest.kt\")\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/test/kotlin/com/saveourtool/diktat/ruleset/chapter3/CollapseIfStatementsRuleWarnTest.kt",
    "content": "package com.saveourtool.diktat.ruleset.chapter3\n\nimport com.saveourtool.diktat.common.config.rules.DIKTAT_RULE_SET_ID\nimport com.saveourtool.diktat.ruleset.constants.Warnings.COLLAPSE_IF_STATEMENTS\nimport com.saveourtool.diktat.ruleset.rules.chapter3.CollapseIfStatementsRule\nimport com.saveourtool.diktat.util.LintTestBase\n\nimport com.saveourtool.diktat.api.DiktatError\nimport generated.WarningNames\nimport org.junit.jupiter.api.Tag\nimport org.junit.jupiter.api.Test\n\nclass CollapseIfStatementsRuleWarnTest : LintTestBase(::CollapseIfStatementsRule) {\n    private val ruleId = \"$DIKTAT_RULE_SET_ID:${CollapseIfStatementsRule.NAME_ID}\"\n\n    @Test\n    @Tag(WarningNames.COLLAPSE_IF_STATEMENTS)\n    fun `one nested if`() {\n        lintMethod(\n            \"\"\"\n            |fun foo () {\n            |     if (true) {\n            |         if (false) {\n            |             doSomething()\n            |         }\n            |     }\n            |\n            |     if (false) {\n            |         someAction()\n            |     } else {\n            |         print(\"some text\")\n            |     }\n            |}\n            \"\"\".trimMargin(),\n            DiktatError(3, 10, ruleId, \"${COLLAPSE_IF_STATEMENTS.warnText()} avoid using redundant nested if-statements\", true)\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.COLLAPSE_IF_STATEMENTS)\n    fun `simple check`() {\n        lintMethod(\n            \"\"\"\n            |fun foo () {\n            |     if (cond1) {\n            |         if (cond2) {\n            |             firstAction()\n            |             secondAction()\n            |         }\n            |     }\n            |     if (cond3) {\n            |         secondAction()\n            |     }\n            |}\n            \"\"\".trimMargin(),\n            DiktatError(3, 10, ruleId, \"${COLLAPSE_IF_STATEMENTS.warnText()} avoid using redundant nested if-statements\", true)\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.COLLAPSE_IF_STATEMENTS)\n    fun `simple check 2`() {\n        lintMethod(\n            \"\"\"\n            |fun foo () {\n            |     if (true) {\n            |\n            |         if (true) {\n            |             doSomething()\n            |         }\n            |     }\n            |}\n            \"\"\".trimMargin(),\n            DiktatError(4, 10, ruleId, \"${COLLAPSE_IF_STATEMENTS.warnText()} avoid using redundant nested if-statements\", true)\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.COLLAPSE_IF_STATEMENTS)\n    fun `nested if with incorrect indention`() {\n        lintMethod(\n            \"\"\"\n            |fun foo () {\n            |     if (true) {\n            |         if (true) {doSomething()}\n            |     }\n            |}\n            \"\"\".trimMargin(),\n            DiktatError(3, 10, ruleId, \"${COLLAPSE_IF_STATEMENTS.warnText()} avoid using redundant nested if-statements\", true)\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.COLLAPSE_IF_STATEMENTS)\n    fun `eol comment`() {\n        lintMethod(\n            \"\"\"\n            |fun foo () {\n            |     if (true) {\n            |         // Some\n            |         // comments\n            |         if (true) {\n            |             doSomething()\n            |         }\n            |     }\n            |}\n            \"\"\".trimMargin(),\n            DiktatError(5, 10, ruleId, \"${COLLAPSE_IF_STATEMENTS.warnText()} avoid using redundant nested if-statements\", true)\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.COLLAPSE_IF_STATEMENTS)\n    fun `block comment`() {\n        lintMethod(\n            \"\"\"\n            |fun foo () {\n            |     if (true) {\n            |         /*\n            |          Some comments\n            |         */\n            |         if (true) {\n            |             doSomething()\n            |         }\n            |     }\n            |}\n            \"\"\".trimMargin(),\n            DiktatError(6, 10, ruleId, \"${COLLAPSE_IF_STATEMENTS.warnText()} avoid using redundant nested if-statements\", true)\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.COLLAPSE_IF_STATEMENTS)\n    fun `kdoc comment`() {\n        lintMethod(\n            \"\"\"\n            |fun foo () {\n            |     if (true) {\n            |         /**\n            |          * Some comments\n            |         */\n            |         if (true) {\n            |             doSomething()\n            |         }\n            |     }\n            |}\n            \"\"\".trimMargin()\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.COLLAPSE_IF_STATEMENTS)\n    fun `combine comments`() {\n        lintMethod(\n            \"\"\"\n            |fun foo () {\n            |     if (true) {\n            |         /*\n            |          Some Comments\n            |         */\n            |         // More comments\n            |         if (true) {\n            |             // comment 1\n            |             val a = 5\n            |             // comment 2\n            |             doSomething()\n            |         }\n            |         // comment 3\n            |     }\n            |}\n            \"\"\".trimMargin(),\n            DiktatError(7, 10, ruleId, \"${COLLAPSE_IF_STATEMENTS.warnText()} avoid using redundant nested if-statements\", true)\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.COLLAPSE_IF_STATEMENTS)\n    fun `comments in compound cond`() {\n        lintMethod(\n            \"\"\"\n            |fun foo() {\n            |     // comment\n            |     if (cond1) {\n            |         /*\n            |          Some comments\n            |         */\n            |         // More comments\n            |         if (cond2 || cond3) {\n            |             doSomething()\n            |         }\n            |     }\n            |}\n            \"\"\".trimMargin(),\n            DiktatError(8, 10, ruleId, \"${COLLAPSE_IF_STATEMENTS.warnText()} avoid using redundant nested if-statements\", true)\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.COLLAPSE_IF_STATEMENTS)\n    fun `comments already in cond`() {\n        lintMethod(\n            \"\"\"\n            |fun foo () {\n            |     if (/*comment*/ true) {\n            |         if (true) {\n            |             doSomething()\n            |         }\n            |     }\n            |}\n            \"\"\".trimMargin(),\n            DiktatError(3, 10, ruleId, \"${COLLAPSE_IF_STATEMENTS.warnText()} avoid using redundant nested if-statements\", true)\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.COLLAPSE_IF_STATEMENTS)\n    fun `comments already in complex cond`() {\n        lintMethod(\n            \"\"\"\n            |fun foo () {\n            |     if (true && (true || false) /*comment*/) {\n            |         if (true /*comment*/) {\n            |             doSomething()\n            |         }\n            |     }\n            |}\n            \"\"\".trimMargin(),\n            DiktatError(3, 10, ruleId, \"${COLLAPSE_IF_STATEMENTS.warnText()} avoid using redundant nested if-statements\", true)\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.COLLAPSE_IF_STATEMENTS)\n    fun `multiline comments already in cond`() {\n        lintMethod(\n            \"\"\"\n            |fun foo () {\n            |     if (true\n            |     /*comment\n            |     * more comments\n            |     */\n            |     ) {\n            |         if (true /*comment 2*/) {\n            |             doSomething()\n            |         }\n            |     }\n            |}\n            \"\"\".trimMargin(),\n            DiktatError(7, 10, ruleId, \"${COLLAPSE_IF_STATEMENTS.warnText()} avoid using redundant nested if-statements\", true)\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.COLLAPSE_IF_STATEMENTS)\n    fun `comments in multiple if-statements`() {\n        lintMethod(\n            \"\"\"\n            |fun foo() {\n            |     if (cond1) {\n            |         // comment\n            |         if (cond2) {\n            |             // comment 2\n            |             if (cond3) {\n            |                 doSomething()\n            |             }\n            |         }\n            |     }\n            |}\n            \"\"\".trimMargin(),\n            DiktatError(4, 10, ruleId, \"${COLLAPSE_IF_STATEMENTS.warnText()} avoid using redundant nested if-statements\", true),\n            DiktatError(6, 14, ruleId, \"${COLLAPSE_IF_STATEMENTS.warnText()} avoid using redundant nested if-statements\", true)\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.COLLAPSE_IF_STATEMENTS)\n    fun `not nested if`() {\n        lintMethod(\n            \"\"\"\n            |fun foo () {\n            |     if (true) {\n            |         val someConstant = 5\n            |         if (true) {\n            |             doSomething()\n            |         }\n            |     }\n            |}\n            \"\"\".trimMargin()\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.COLLAPSE_IF_STATEMENTS)\n    fun `internal if with else branch`() {\n        lintMethod(\n            \"\"\"\n            |fun foo () {\n            |     if (cond1) {\n            |         if (cond2) {\n            |             firstAction()\n            |             secondAction()\n            |         } else {\n            |             firstAction()\n            |         }\n            |     } else {\n            |         secondAction()\n            |     }\n            |}\n            \"\"\".trimMargin(),\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.COLLAPSE_IF_STATEMENTS)\n    fun `internal if with multiple else and elif branches`() {\n        lintMethod(\n            \"\"\"\n            |fun foo () {\n            |     if (cond1) {\n            |         if (cond2) {\n            |             firstAction()\n            |             secondAction()\n            |         } else if (cond3) {\n            |             firstAction()\n            |         } else {\n            |             val a = 5\n            |         }\n            |     } else {\n            |         secondAction()\n            |     }\n            |}\n            \"\"\".trimMargin()\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.COLLAPSE_IF_STATEMENTS)\n    fun `if isn't last child`() {\n        lintMethod(\n            \"\"\"\n            |fun foo() {\n            |   if (cond1) {\n            |       if (cond2) {\n            |            doSomething()\n            |       }\n            |       val a = 5\n            |   }\n            |}\n            \"\"\".trimMargin()\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.COLLAPSE_IF_STATEMENTS)\n    fun `external if with else branch`() {\n        lintMethod(\n            \"\"\"\n            |fun foo() {\n            |   if (cond1) {\n            |       if (cond2) {\n            |            doSomething()\n            |       }\n            |   } else {\n            |       val b = 1\n            |   }\n            |}\n            \"\"\".trimMargin()\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.COLLAPSE_IF_STATEMENTS)\n    fun `external if with else node, but exist nested if`() {\n        lintMethod(\n            \"\"\"\n            |fun foo() {\n            |   val a = 0\n            |   if (cond1) {\n            |       if (cond2) {\n            |           if (cond3) {\n            |               doSomething()\n            |           }\n            |       }\n            |   } else {\n            |       val b = 1\n            |   }\n            |}\n            \"\"\".trimMargin(),\n            DiktatError(5, 12, ruleId, \"${COLLAPSE_IF_STATEMENTS.warnText()} avoid using redundant nested if-statements\", true),\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.COLLAPSE_IF_STATEMENTS)\n    fun `three if statements`() {\n        lintMethod(\n            \"\"\"\n            |fun foo () {\n            |     if (true) {\n            |         if (true) {\n            |             if (true) {\n            |                 doSomething()\n            |             }\n            |         }\n            |     }\n            |}\n            \"\"\".trimMargin(),\n            DiktatError(3, 10, ruleId, \"${COLLAPSE_IF_STATEMENTS.warnText()} avoid using redundant nested if-statements\", true),\n            DiktatError(4, 14, ruleId, \"${COLLAPSE_IF_STATEMENTS.warnText()} avoid using redundant nested if-statements\", true)\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.COLLAPSE_IF_STATEMENTS)\n    fun `many if statements`() {\n        lintMethod(\n            \"\"\"\n            |fun foo () {\n            |     if (true) {\n            |         if (true) {\n            |             if (true) {\n            |                 if (true) {\n            |                     if (true) {\n            |                         if (true) {\n            |                             doSomething()\n            |                         }\n            |                     }\n            |                 }\n            |             }\n            |         }\n            |     }\n            |}\n            \"\"\".trimMargin(),\n            DiktatError(3, 10, ruleId, \"${COLLAPSE_IF_STATEMENTS.warnText()} avoid using redundant nested if-statements\", true),\n            DiktatError(4, 14, ruleId, \"${COLLAPSE_IF_STATEMENTS.warnText()} avoid using redundant nested if-statements\", true),\n            DiktatError(5, 18, ruleId, \"${COLLAPSE_IF_STATEMENTS.warnText()} avoid using redundant nested if-statements\", true),\n            DiktatError(6, 22, ruleId, \"${COLLAPSE_IF_STATEMENTS.warnText()} avoid using redundant nested if-statements\", true),\n            DiktatError(7, 26, ruleId, \"${COLLAPSE_IF_STATEMENTS.warnText()} avoid using redundant nested if-statements\", true)\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.COLLAPSE_IF_STATEMENTS)\n    fun `not nested else if statement`() {\n        lintMethod(\n            \"\"\"\n            |fun foo() {\n            |    fun1()\n            |    if (cond1) {\n            |        fun2()\n            |    } else if (cond2) {\n            |        if (true) {\n            |            fun3()\n            |        }\n            |    } else {\n            |        fun4()\n            |    }\n            |}\n            \"\"\".trimMargin()\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.COLLAPSE_IF_STATEMENTS)\n    fun `nested else if statement`() {\n        lintMethod(\n            \"\"\"\n            |fun foo() {\n            |    fun1()\n            |    if (cond1) {\n            |        fun2()\n            |    } else if (cond2) {\n            |        if (true) {\n            |           if (true) {\n            |               fun3()\n            |           }\n            |        }\n            |    } else {\n            |        fun4()\n            |    }\n            |}\n            \"\"\".trimMargin(),\n            DiktatError(7, 12, ruleId, \"${COLLAPSE_IF_STATEMENTS.warnText()} avoid using redundant nested if-statements\", true),\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.COLLAPSE_IF_STATEMENTS)\n    fun `compound condition`() {\n        lintMethod(\n            \"\"\"\n            |fun foo () {\n            |     if (cond1) {\n            |         if (cond2 || cond3) {\n            |             firstAction()\n            |             secondAction()\n            |         }\n            |     }\n            |     if (cond4) {\n            |         secondAction()\n            |     }\n            |}\n            \"\"\".trimMargin(),\n            DiktatError(3, 10, ruleId, \"${COLLAPSE_IF_STATEMENTS.warnText()} avoid using redundant nested if-statements\", true),\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.COLLAPSE_IF_STATEMENTS)\n    fun `not nested compound condition`() {\n        lintMethod(\n            \"\"\"\n            |fun foo () {\n            |     if (cond1) {\n            |         if (cond2 || cond3) {\n            |             firstAction()\n            |             secondAction()\n            |         }\n            |         if (cond4) {\n            |             secondAction()\n            |         }\n            |     }\n            |}\n            \"\"\".trimMargin()\n        )\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/test/kotlin/com/saveourtool/diktat/ruleset/chapter3/ConsecutiveSpacesRuleFixTest.kt",
    "content": "package com.saveourtool.diktat.ruleset.chapter3\n\nimport com.saveourtool.diktat.common.config.rules.RulesConfig\nimport com.saveourtool.diktat.ruleset.constants.Warnings\nimport com.saveourtool.diktat.ruleset.rules.chapter3.ConsecutiveSpacesRule\nimport com.saveourtool.diktat.util.FixTestBase\n\nimport generated.WarningNames\nimport org.junit.jupiter.api.Tag\nimport org.junit.jupiter.api.Test\n\nclass ConsecutiveSpacesRuleFixTest : FixTestBase(\"test/paragraph3/spaces\",\n    ::ConsecutiveSpacesRule,\n    listOf(\n        RulesConfig(Warnings.TOO_MANY_CONSECUTIVE_SPACES.name, true,\n            mapOf(\n                \"maxSpaces\" to \"1\",\n                \"saveInitialFormattingForEnums\" to \"true\"\n            )\n        )\n    )\n) {\n    @Test\n    @Tag(WarningNames.TOO_MANY_CONSECUTIVE_SPACES)\n    fun `many spaces rule enum case`() {\n        fixAndCompare(\"TooManySpacesEnumExpected.kt\", \"TooManySpacesEnumTest.kt\")\n    }\n\n    @Test\n    @Tag(WarningNames.TOO_MANY_CONSECUTIVE_SPACES)\n    fun `many spaces rule`() {\n        fixAndCompare(\"TooManySpacesExpected.kt\", \"TooManySpacesTest.kt\")\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/test/kotlin/com/saveourtool/diktat/ruleset/chapter3/ConsecutiveSpacesRuleWarnTest.kt",
    "content": "package com.saveourtool.diktat.ruleset.chapter3\n\nimport com.saveourtool.diktat.common.config.rules.DIKTAT_RULE_SET_ID\nimport com.saveourtool.diktat.common.config.rules.RulesConfig\nimport com.saveourtool.diktat.ruleset.constants.Warnings.TOO_MANY_CONSECUTIVE_SPACES\nimport com.saveourtool.diktat.ruleset.rules.chapter3.ConsecutiveSpacesRule\nimport com.saveourtool.diktat.util.LintTestBase\n\nimport com.saveourtool.diktat.api.DiktatError\nimport generated.WarningNames\nimport org.junit.jupiter.api.Tag\nimport org.junit.jupiter.api.Test\n\nclass ConsecutiveSpacesRuleWarnTest : LintTestBase(::ConsecutiveSpacesRule) {\n    private val ruleId = \"$DIKTAT_RULE_SET_ID:${ConsecutiveSpacesRule.NAME_ID}\"\n    private val rulesConfigListNoSpaces: List<RulesConfig> = listOf(\n        RulesConfig(TOO_MANY_CONSECUTIVE_SPACES.name, true,\n            mapOf(\"maxSpaces\" to \"2\"))\n    )\n\n    @Test\n    @Tag(WarningNames.TOO_MANY_CONSECUTIVE_SPACES)\n    fun `enum spaces check bad`() {\n        lintMethod(\n            \"\"\"\n                    |enum       class IntArithmetics : BinaryOperator<Int> {\n                    |    PLUS, ASD\n                    |}\n            \"\"\".trimMargin(),\n            DiktatError(1, 5, ruleId, \"${TOO_MANY_CONSECUTIVE_SPACES.warnText()} found: 7. need to be: 1\", true)\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.TOO_MANY_CONSECUTIVE_SPACES)\n    fun `enum spaces check good`() {\n        lintMethod(\n            \"\"\"\n                    |enum class SomeEnum {\n                    |    PLUS\n                    |}\n            \"\"\".trimMargin()\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.TOO_MANY_CONSECUTIVE_SPACES)\n    fun `fun space check good`() {\n        lintMethod(\n            \"\"\"\n                    |class A {\n                    |   fun testFunction(val a = 5) {\n                    |   }\n                    |}\n            \"\"\".trimMargin()\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.TOO_MANY_CONSECUTIVE_SPACES)\n    fun `fun space check bad`() {\n        lintMethod(\n            \"\"\"\n                    |class A {\n                    |   fun      testFunction(val a =     6) {\n                    |   }\n                    |}\n            \"\"\".trimMargin(),\n            DiktatError(2, 7, ruleId, \"${TOO_MANY_CONSECUTIVE_SPACES.warnText()} found: 6. need to be: 1\", true),\n            DiktatError(2, 33, ruleId, \"${TOO_MANY_CONSECUTIVE_SPACES.warnText()} found: 5. need to be: 1\", true)\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.TOO_MANY_CONSECUTIVE_SPACES)\n    fun `class space check bad`() {\n        lintMethod(\n            \"\"\"\n                    |class     SomeClass {\n                    |   inner     class InnerClass{\n                    |   }\n                    |}\n            \"\"\".trimMargin(),\n            DiktatError(1, 6, ruleId, \"${TOO_MANY_CONSECUTIVE_SPACES.warnText()} found: 5. need to be: 1\", true),\n            DiktatError(2, 9, ruleId, \"${TOO_MANY_CONSECUTIVE_SPACES.warnText()} found: 5. need to be: 1\", true)\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.TOO_MANY_CONSECUTIVE_SPACES)\n    fun `class space check good`() {\n        lintMethod(\n            \"\"\"\n                    |class SomeClass {\n                    |   inner class InnerClass{\n                    |   }\n                    |}\n            \"\"\".trimMargin()\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.TOO_MANY_CONSECUTIVE_SPACES)\n    fun `property space check good`() {\n        lintMethod(\n            \"\"\"\n                    |class SomeClass {\n                    |   fun someFunc() {\n                    |       val a = 5\n                    |       val b: Int = 3\n                    |       val c: Int\n                    |   }\n                    |}\n            \"\"\".trimMargin()\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.TOO_MANY_CONSECUTIVE_SPACES)\n    fun `property space check bad`() {\n        lintMethod(\n            \"\"\"\n                    |class SomeClass {\n                    |   fun someFunc() {\n                    |       val a =    5\n                    |       val b: Int     = 3\n                    |       val c:     Int\n                    |   }\n                    |}\n            \"\"\".trimMargin(),\n            DiktatError(3, 15, ruleId, \"${TOO_MANY_CONSECUTIVE_SPACES.warnText()} found: 4. need to be: 1\", true),\n            DiktatError(4, 18, ruleId, \"${TOO_MANY_CONSECUTIVE_SPACES.warnText()} found: 5. need to be: 1\", true),\n            DiktatError(5, 14, ruleId, \"${TOO_MANY_CONSECUTIVE_SPACES.warnText()} found: 5. need to be: 1\", true)\n\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.TOO_MANY_CONSECUTIVE_SPACES)\n    fun `generic space check good`() {\n        lintMethod(\n            \"\"\"\n                    |class Box<T>(t: T){\n                    |   var value = t\n                    |}\n            \"\"\".trimMargin()\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.TOO_MANY_CONSECUTIVE_SPACES)\n    fun `generic space check bad`() {\n        lintMethod(\n            \"\"\"\n                    |class Box<   T>(t:    T){\n                    |   var value = t\n                    |}\n            \"\"\".trimMargin(),\n            DiktatError(1, 11, ruleId, \"${TOO_MANY_CONSECUTIVE_SPACES.warnText()} found: 3. need to be: 1\", true),\n            DiktatError(1, 19, ruleId, \"${TOO_MANY_CONSECUTIVE_SPACES.warnText()} found: 4. need to be: 1\", true)\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.TOO_MANY_CONSECUTIVE_SPACES)\n    fun `interface space check good`() {\n        lintMethod(\n            \"\"\"\n                    |interface TestInterface{\n                    |   fun foo()\n                    |   fun bar()\n                    |}\n            \"\"\".trimMargin()\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.TOO_MANY_CONSECUTIVE_SPACES)\n    fun `interface space check bad`() {\n        lintMethod(\n            \"\"\"\n                    |interface       TestInterface{\n                    |   fun foo()\n                    |   fun bar()\n                    |}\n            \"\"\".trimMargin(),\n            DiktatError(1, 10, ruleId, \"${TOO_MANY_CONSECUTIVE_SPACES.warnText()} found: 7. need to be: 1\", true)\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.TOO_MANY_CONSECUTIVE_SPACES)\n    fun `init space check bad`() {\n        lintMethod(\n            \"\"\"\n                    |class SomeClass{\n                    |   init     {\n                    |       print(\"SomeThing\")\n                    |   }\n                    |}\n            \"\"\".trimMargin(),\n            DiktatError(2, 8, ruleId, \"${TOO_MANY_CONSECUTIVE_SPACES.warnText()} found: 5. need to be: 1\", true)\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.TOO_MANY_CONSECUTIVE_SPACES)\n    fun `init space check good`() {\n        lintMethod(\n            \"\"\"\n                    |class SomeClass{\n                    |   init {\n                    |       print(\"SomeThing\")\n                    |   }\n                    |}\n            \"\"\".trimMargin()\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.TOO_MANY_CONSECUTIVE_SPACES)\n    fun `config check`() {\n        lintMethod(\n            \"\"\"\n                    |class  SomeClass  {\n                    |   init  {\n                    |       print(\"SomeThing\")\n                    |   }\n                    |}\n            \"\"\".trimMargin(),\n            rulesConfigList = rulesConfigListNoSpaces\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.TOO_MANY_CONSECUTIVE_SPACES)\n    fun `eol comment check`() {\n        lintMethod(\n            \"\"\"\n                    |class SomeClass{              // this is a comment\n                    |   val a = 5 // this is another comment\n                    |}\n            \"\"\".trimMargin()\n        )\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/test/kotlin/com/saveourtool/diktat/ruleset/chapter3/DebugPrintRuleWarnTest.kt",
    "content": "package com.saveourtool.diktat.ruleset.chapter3\n\nimport com.saveourtool.diktat.common.config.rules.DIKTAT_RULE_SET_ID\nimport com.saveourtool.diktat.ruleset.constants.Warnings\nimport com.saveourtool.diktat.ruleset.rules.chapter3.DebugPrintRule\nimport com.saveourtool.diktat.util.LintTestBase\n\nimport com.saveourtool.diktat.api.DiktatError\nimport generated.WarningNames\nimport org.junit.jupiter.api.Tag\nimport org.junit.jupiter.api.Test\n\nclass DebugPrintRuleWarnTest : LintTestBase(::DebugPrintRule) {\n    private val ruleId = \"$DIKTAT_RULE_SET_ID:${DebugPrintRule.NAME_ID}\"\n\n    @Test\n    @Tag(WarningNames.DEBUG_PRINT)\n    fun `call of print`() {\n        lintMethod(\n            \"\"\"\n                |fun test() {\n                |    print(\"test print\")\n                |}\n            \"\"\".trimMargin(),\n            DiktatError(2, 5, ruleId, \"${Warnings.DEBUG_PRINT.warnText()} found print()\", false)\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.DEBUG_PRINT)\n    fun `call of println`() {\n        lintMethod(\n            \"\"\"\n                |fun test() {\n                |    println(\"test println\")\n                |}\n            \"\"\".trimMargin(),\n            DiktatError(2, 5, ruleId, \"${Warnings.DEBUG_PRINT.warnText()} found println()\", false)\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.DEBUG_PRINT)\n    fun `call of println without arguments`() {\n        lintMethod(\n            \"\"\"\n                |fun test() {\n                |    println()\n                |}\n            \"\"\".trimMargin(),\n            DiktatError(2, 5, ruleId, \"${Warnings.DEBUG_PRINT.warnText()} found println()\", false)\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.DEBUG_PRINT)\n    fun `custom method print by argument list`() {\n        lintMethod(\n            \"\"\"\n                |fun test() {\n                |    print(\"test custom args\", 123)\n                |}\n            \"\"\".trimMargin()\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.DEBUG_PRINT)\n    fun `custom method print with lambda as last parameter`() {\n        lintMethod(\n            \"\"\"\n                |fun test() {\n                |    print(\"test custom method\") {\n                |       foo(\"\")\n                |    }\n                |}\n            \"\"\".trimMargin()\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.DEBUG_PRINT)\n    fun `custom method print in another object`() {\n        lintMethod(\n            \"\"\"\n                |fun test() {\n                |    foo.print(\"test custom method\")\n                |}\n            \"\"\".trimMargin()\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.DEBUG_PRINT)\n    fun `call of console`() {\n        lintMethod(\n            \"\"\"\n                |fun test() {\n                |    console.error(\"1\")\n                |    console.info(\"1\", \"2\")\n                |    console.log(\"1\", \"2\", \"3\")\n                |    console.warn(\"1\", \"2\", \"3\", \"4\")\n                |}\n            \"\"\".trimMargin(),\n            DiktatError(2, 5, ruleId, \"${Warnings.DEBUG_PRINT.warnText()} found console.error()\", false),\n            DiktatError(3, 5, ruleId, \"${Warnings.DEBUG_PRINT.warnText()} found console.info()\", false),\n            DiktatError(4, 5, ruleId, \"${Warnings.DEBUG_PRINT.warnText()} found console.log()\", false),\n            DiktatError(5, 5, ruleId, \"${Warnings.DEBUG_PRINT.warnText()} found console.warn()\", false)\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.DEBUG_PRINT)\n    fun `custom method console with lambda as last parameter`() {\n        lintMethod(\n            \"\"\"\n                |fun test() {\n                |    console.error(\"1\") {\n                |       foo(\"\")\n                |    }\n                |    console.info(\"1\", \"2\") {\n                |       foo(\"\")\n                |    }\n                |    console.log(\"1\", \"2\", \"3\") {\n                |       foo(\"\")\n                |    }\n                |    console.warn(\"1\", \"2\", \"3\", \"4\") {\n                |       foo(\"\")\n                |    }\n                |}\n            \"\"\".trimMargin()\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.DEBUG_PRINT)\n    fun `call parameter from console`() {\n        lintMethod(\n            \"\"\"\n                |fun test() {\n                |    val foo = console.size\n                |}\n            \"\"\".trimMargin()\n        )\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/test/kotlin/com/saveourtool/diktat/ruleset/chapter3/EmptyBlockFixTest.kt",
    "content": "package com.saveourtool.diktat.ruleset.chapter3\n\nimport com.saveourtool.diktat.common.config.rules.RulesConfig\nimport com.saveourtool.diktat.ruleset.constants.Warnings\nimport com.saveourtool.diktat.ruleset.rules.chapter3.EmptyBlock\nimport com.saveourtool.diktat.util.FixTestBase\n\nimport generated.WarningNames\nimport org.junit.jupiter.api.Tag\nimport org.junit.jupiter.api.Test\n\nclass EmptyBlockFixTest : FixTestBase(\"test/paragraph3/empty_block\", ::EmptyBlock) {\n    private val rulesConfigListEmptyBlockExist: List<RulesConfig> = listOf(\n        RulesConfig(Warnings.EMPTY_BLOCK_STRUCTURE_ERROR.name, true,\n            mapOf(\"allowEmptyBlocks\" to \"True\"))\n    )\n\n    @Test\n    @Tag(WarningNames.EMPTY_BLOCK_STRUCTURE_ERROR)\n    fun `should fix open and close brace in different expression`() {\n        fixAndCompare(\"EmptyBlockExpected.kt\", \"EmptyBlockTest.kt\", rulesConfigListEmptyBlockExist)\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/test/kotlin/com/saveourtool/diktat/ruleset/chapter3/EmptyBlockWarnTest.kt",
    "content": "package com.saveourtool.diktat.ruleset.chapter3\n\nimport com.saveourtool.diktat.common.config.rules.DIKTAT_RULE_SET_ID\nimport com.saveourtool.diktat.common.config.rules.RulesConfig\nimport com.saveourtool.diktat.ruleset.constants.Warnings.EMPTY_BLOCK_STRUCTURE_ERROR\nimport com.saveourtool.diktat.ruleset.rules.chapter3.EmptyBlock\nimport com.saveourtool.diktat.util.LintTestBase\n\nimport com.saveourtool.diktat.api.DiktatError\nimport generated.WarningNames\nimport org.junit.jupiter.api.Tag\nimport org.junit.jupiter.api.Test\n\nclass EmptyBlockWarnTest : LintTestBase(::EmptyBlock) {\n    private val ruleId = \"$DIKTAT_RULE_SET_ID:${EmptyBlock.NAME_ID}\"\n    private val rulesConfigListIgnoreEmptyBlock: List<RulesConfig> = listOf(\n        RulesConfig(EMPTY_BLOCK_STRUCTURE_ERROR.name, true,\n            mapOf(\"styleEmptyBlockWithNewline\" to \"False\"))\n    )\n    private val rulesConfigListEmptyBlockExist: List<RulesConfig> = listOf(\n        RulesConfig(EMPTY_BLOCK_STRUCTURE_ERROR.name, true,\n            mapOf(\"allowEmptyBlocks\" to \"True\"))\n    )\n\n    @Test\n    @Tag(WarningNames.EMPTY_BLOCK_STRUCTURE_ERROR)\n    fun `check if expression with empty else block`() {\n        lintMethod(\n            \"\"\"\n                    |fun foo() {\n                    |    if (x < -5) {\n                    |       goo()\n                    |    }\n                    |    else {\n                    |    }\n                    |}\n            \"\"\".trimMargin(),\n            DiktatError(5, 10, ruleId, \"${EMPTY_BLOCK_STRUCTURE_ERROR.warnText()} empty blocks are forbidden unless it is function with override keyword\", false)\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.EMPTY_BLOCK_STRUCTURE_ERROR)\n    fun `check if WHEN element node text is empty`() {\n        lintMethod(\n            \"\"\"\n                    |fun foo() {\n                    |    when (a) {\n                    |    }\n                    |}\n            \"\"\".trimMargin(),\n            DiktatError(2, 5, ruleId, \"${EMPTY_BLOCK_STRUCTURE_ERROR.warnText()} empty blocks are forbidden unless it is function with override keyword\", false)\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.EMPTY_BLOCK_STRUCTURE_ERROR)\n    fun `check if expression with empty else block with config`() {\n        lintMethod(\n            \"\"\"\n                    |fun foo() {\n                    |    if (x < -5) {\n                    |       goo()\n                    |    }\n                    |    else {}\n                    |}\n            \"\"\".trimMargin(),\n            DiktatError(5, 10, ruleId, \"${EMPTY_BLOCK_STRUCTURE_ERROR.warnText()} empty blocks are forbidden unless it is function with override keyword\", false),\n            rulesConfigList = rulesConfigListIgnoreEmptyBlock\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.EMPTY_BLOCK_STRUCTURE_ERROR)\n    fun `check fun expression with empty block and override annotation`() {\n        lintMethod(\n            \"\"\"\n                    |override fun foo() {\n                    |}\n            \"\"\".trimMargin()\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.EMPTY_BLOCK_STRUCTURE_ERROR)\n    fun `check if expression with empty else block but with permission to use empty block`() {\n        lintMethod(\n            \"\"\"\n                    |fun foo() {\n                    |    if (x < -5) {\n                    |       goo()\n                    |    }\n                    |    else {\n                    |    }\n                    |}\n            \"\"\".trimMargin(),\n            rulesConfigList = rulesConfigListEmptyBlockExist\n        )\n    }\n\n    @Test\n    fun `check if expression without block`() {\n        lintMethod(\n            \"\"\"\n                    |fun foo() {\n                    |   if (node.treeParent != null) return\n                    |}\n            \"\"\".trimMargin()\n        )\n    }\n\n    @Test\n    fun `empty lambda`() {\n        lintMethod(\n            \"\"\"\n                    |fun foo() {\n                    |   run { }\n                    |}\n            \"\"\".trimMargin(),\n            rulesConfigList = rulesConfigListEmptyBlockExist\n        )\n    }\n\n    @Test\n    fun `check if-else expression without block`() {\n        lintMethod(\n            \"\"\"\n                    |fun foo() {\n                    |   if (node.treeParent != null) return else println(true)\n                    |}\n            \"\"\".trimMargin()\n        )\n    }\n\n    @Test\n    fun `check for expresion and while without block`() {\n        lintMethod(\n            \"\"\"\n                    |fun foo() {\n                    |   for(x in 0..10) println(x)\n                    |   val x = 10\n                    |   while (x > 0)\n                    |       --x\n                    |}\n            \"\"\".trimMargin()\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.EMPTY_BLOCK_STRUCTURE_ERROR)\n    fun `check empty lambda with config`() {\n        lintMethod(\n            \"\"\"\n                |fun foo() {\n                |   val y = listOf<Int>().map {\n                |\n                |   }\n                |}\n            \"\"\".trimMargin(),\n            DiktatError(2, 30, ruleId, \"${EMPTY_BLOCK_STRUCTURE_ERROR.warnText()} do not put newlines in empty lambda\", true),\n            rulesConfigList = rulesConfigListEmptyBlockExist\n        )\n    }\n\n    @Test\n    fun `check empty lambda`() {\n        lintMethod(\n            \"\"\"\n                    |fun foo() {\n                    |   val y = listOf<Int>().map { }\n                    |}\n            \"\"\".trimMargin(),\n            DiktatError(2, 30, ruleId, \"${EMPTY_BLOCK_STRUCTURE_ERROR.warnText()} empty blocks are forbidden unless it is function with override keyword\", false)\n        )\n    }\n\n    @Test\n    fun `should not trigger on anonymous SAM classes #1`() {\n        lintMethod(\n            \"\"\"\n                |fun foo() {\n                |   val proj = some.create(\n                |       Disposable {},\n                |       config\n                |   ).project\n                |}\n            \"\"\".trimMargin(),\n            rulesConfigList = rulesConfigListEmptyBlockExist\n        )\n    }\n\n    @Test\n    fun `should not trigger on anonymous SAM classes #2`() {\n        lintMethod(\n            \"\"\"\n                |fun foo() {\n                |   val some = Disposable {}\n                |   val proj = some.create(\n                |       some,\n                |       config\n                |   ).project\n                |}\n            \"\"\".trimMargin(),\n            rulesConfigList = rulesConfigListEmptyBlockExist\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.EMPTY_BLOCK_STRUCTURE_ERROR)\n    fun `should trigger on implementing anonymous SAM classes`() {\n        lintMethod(\n            \"\"\"\n                |interface A\n                |\n                |val some = object : A{}\n            \"\"\".trimMargin(),\n            DiktatError(3, 22, ruleId, \"${EMPTY_BLOCK_STRUCTURE_ERROR.warnText()} different style for empty block\", true),\n            rulesConfigList = rulesConfigListEmptyBlockExist\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.EMPTY_BLOCK_STRUCTURE_ERROR)\n    fun `should not trigger on empty lambdas as a functions`() {\n        lintMethod(\n            \"\"\"\n                |fun foo(bar: () -> Unit = {})\n                |\n                |class Some {\n                |   fun bar() {\n                |       A({})\n                |   }\n                |}\n            \"\"\".trimMargin(),\n            rulesConfigList = rulesConfigListEmptyBlockExist\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.EMPTY_BLOCK_STRUCTURE_ERROR)\n    fun `should not trigger on empty lambdas as a functions #2`() {\n        lintMethod(\n            \"\"\"\n                |fun some() {\n                |    val project = KotlinCoreEnvironment.createForProduction(\n                |       { },\n                |       compilerConfiguration,\n                |       EnvironmentConfigFiles.JVM_CONFIG_FILES\n                |    ).project\n                |}\n            \"\"\".trimMargin(),\n            rulesConfigList = rulesConfigListEmptyBlockExist\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.EMPTY_BLOCK_STRUCTURE_ERROR)\n    fun `should not trigger on KotlinLogging logger`() {\n        lintMethod(\n            \"\"\"\n                |import io.github.oshai.kotlinlogging.KotlinLogging\n                |\n                |fun some() {\n                |    val log = KotlinLogging.logger {}\n                |    log.info { \"test\" }\n                |}\n            \"\"\".trimMargin(),\n        )\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/test/kotlin/com/saveourtool/diktat/ruleset/chapter3/EnumsSeparatedFixTest.kt",
    "content": "package com.saveourtool.diktat.ruleset.chapter3\n\nimport com.saveourtool.diktat.ruleset.rules.chapter3.EnumsSeparated\nimport com.saveourtool.diktat.util.FixTestBase\n\nimport generated.WarningNames\nimport org.junit.jupiter.api.Tag\nimport org.junit.jupiter.api.Test\n\nclass EnumsSeparatedFixTest : FixTestBase(\"test/paragraph3/enum_separated\", ::EnumsSeparated) {\n    @Test\n    @Tag(WarningNames.ENUMS_SEPARATED)\n    fun `test enums split`() {\n        fixAndCompare(\"EnumSeparatedExpected.kt\", \"EnumSeparatedTest.kt\")\n    }\n\n    @Test\n    @Tag(WarningNames.ENUMS_SEPARATED)\n    fun `last element with comment`() {\n        fixAndCompare(\"LastElementCommentExpected.kt\", \"LastElementCommentTest.kt\")\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/test/kotlin/com/saveourtool/diktat/ruleset/chapter3/EnumsSeparatedWarnTest.kt",
    "content": "package com.saveourtool.diktat.ruleset.chapter3\n\nimport com.saveourtool.diktat.common.config.rules.DIKTAT_RULE_SET_ID\nimport com.saveourtool.diktat.ruleset.constants.Warnings.ENUMS_SEPARATED\nimport com.saveourtool.diktat.ruleset.rules.chapter3.EnumsSeparated\nimport com.saveourtool.diktat.util.LintTestBase\n\nimport com.saveourtool.diktat.api.DiktatError\nimport generated.WarningNames\nimport org.junit.jupiter.api.Tag\nimport org.junit.jupiter.api.Test\n\nclass EnumsSeparatedWarnTest : LintTestBase(::EnumsSeparated) {\n    private val ruleId = \"$DIKTAT_RULE_SET_ID:${EnumsSeparated.NAME_ID}\"\n\n    @Test\n    @Tag(WarningNames.ENUMS_SEPARATED)\n    fun `check simple correct enum with new line`() {\n        lintMethod(\n            \"\"\"\n                    |enum class ENUM {\n                    |   A,\n                    |   B,\n                    |   C,\n                    |   ;\n                    |}\n            \"\"\".trimMargin()\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.ENUMS_SEPARATED)\n    fun `check simple correct enum with comments`() {\n        lintMethod(\n            \"\"\"\n                    |enum class ENUM {\n                    |   A, // this is A\n                    |   B,\n                    |   C,\n                    |   ;\n                    |}\n            \"\"\".trimMargin()\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.ENUMS_SEPARATED)\n    fun `check simple enum but with fun`() {\n        lintMethod(\n            \"\"\"\n                    |enum class ENUM {\n                    |   A, B, C;\n                    |   fun foo() {}\n                    |}\n            \"\"\".trimMargin(),\n            DiktatError(2, 4, ruleId, \"${ENUMS_SEPARATED.warnText()} enum entries must end with a line break\", true),\n            DiktatError(2, 7, ruleId, \"${ENUMS_SEPARATED.warnText()} enum entries must end with a line break\", true),\n            DiktatError(2, 10, ruleId, \"${ENUMS_SEPARATED.warnText()} semicolon must be on a new line\", true),\n            DiktatError(2, 10, ruleId, \"${ENUMS_SEPARATED.warnText()} last enum entry must end with a comma\", true)\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.ENUMS_SEPARATED)\n    fun `check one line enum`() {\n        lintMethod(\n            \"\"\"\n                    |enum class ENUM {\n                    |   A, B, C\n                    |}\n            \"\"\".trimMargin()\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.ENUMS_SEPARATED)\n    fun `check wrong simple enum with new line last value`() {\n        lintMethod(\n            \"\"\"\n                    |enum class ENUM {\n                    |   A, B,\n                    |   C\n                    |}\n            \"\"\".trimMargin(),\n            DiktatError(2, 4, ruleId, \"${ENUMS_SEPARATED.warnText()} enum entries must end with a line break\", true),\n            DiktatError(3, 4, ruleId, \"${ENUMS_SEPARATED.warnText()} enums must end with semicolon\", true),\n            DiktatError(3, 4, ruleId, \"${ENUMS_SEPARATED.warnText()} last enum entry must end with a comma\", true)\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.ENUMS_SEPARATED)\n    fun `check wrong simple enum with new line last value but with same line semicolon`() {\n        lintMethod(\n            \"\"\"\n                    |enum class ENUM {\n                    |   A, B,\n                    |   C, ;\n                    |}\n            \"\"\".trimMargin(),\n            DiktatError(2, 4, ruleId, \"${ENUMS_SEPARATED.warnText()} enum entries must end with a line break\", true),\n            DiktatError(3, 4, ruleId, \"${ENUMS_SEPARATED.warnText()} semicolon must be on a new line\", true)\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.ENUMS_SEPARATED)\n    fun `check correct enum but with initialize entries`() {\n        lintMethod(\n            \"\"\"\n                    |enum class ENUM {\n                    |   RED(0xFF0000),\n                    |   GREEN(0x00FF00),\n                    |   BLUE(0x0000FF),\n                    |   ;\n                    |}\n            \"\"\".trimMargin()\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.ENUMS_SEPARATED)\n    fun `check wrong enum with initialize entries and without last comma`() {\n        lintMethod(\n            \"\"\"\n                    |enum class ENUM {\n                    |   RED(0xFF0000),\n                    |   GREEN(0x00FF00),\n                    |   BLUE(0x0000FF)\n                    |   ;\n                    |}\n            \"\"\".trimMargin(),\n            DiktatError(4, 4, ruleId, \"${ENUMS_SEPARATED.warnText()} last enum entry must end with a comma\", true)\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.ENUMS_SEPARATED)\n    fun `check correct enum with method`() {\n        lintMethod(\n            \"\"\"\n                    |enum class Warnings {\n                    |   WAITING {\n                    |      override fun signal() = TALKING\n                    |   },\n                    |   TALKING  {\n                    |      override fun signal() = TALKING\n                    |   },\n                    |   ;\n                    |   abstract fun signal(): ProtocolState\n                    |}\n            \"\"\".trimMargin()\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.ENUMS_SEPARATED)\n    fun `check wrong enum without last comma and line break`() {\n        lintMethod(\n            \"\"\"\n                    |enum class Warnings {\n                    |   WAITING {\n                    |      override fun signal() = TALKING\n                    |   },\n                    |   TALKING  {\n                    |      override fun signal() = TALKING\n                    |   };\n                    |   abstract fun signal(): ProtocolState\n                    |}\n            \"\"\".trimMargin(),\n            DiktatError(5, 4, ruleId, \"${ENUMS_SEPARATED.warnText()} semicolon must be on a new line\", true),\n            DiktatError(5, 4, ruleId, \"${ENUMS_SEPARATED.warnText()} last enum entry must end with a comma\", true)\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.ENUMS_SEPARATED)\n    fun `check wrong enum without last comma, line break and semicolon`() {\n        lintMethod(\n            \"\"\"\n                    |enum class Warnings {\n                    |   WAITING {\n                    |      override fun signal() = TALKING\n                    |   },\n                    |   TALKING  {\n                    |      override fun signal() = TALKING\n                    |   }\n                    |}\n            \"\"\".trimMargin(),\n            DiktatError(5, 4, ruleId, \"${ENUMS_SEPARATED.warnText()} enums must end with semicolon\", true),\n            DiktatError(5, 4, ruleId, \"${ENUMS_SEPARATED.warnText()} last enum entry must end with a comma\", true)\n\n        )\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/test/kotlin/com/saveourtool/diktat/ruleset/chapter3/FileSizeWarnTest.kt",
    "content": "package com.saveourtool.diktat.ruleset.chapter3\n\nimport com.saveourtool.diktat.common.config.rules.DIKTAT_RULE_SET_ID\nimport com.saveourtool.diktat.common.config.rules.RulesConfig\nimport com.saveourtool.diktat.ruleset.constants.Warnings\nimport com.saveourtool.diktat.ruleset.rules.chapter3.files.FileSize\nimport com.saveourtool.diktat.util.LintTestBase\n\nimport com.saveourtool.diktat.api.DiktatError\nimport generated.WarningNames\nimport org.junit.jupiter.api.Tag\nimport org.junit.jupiter.api.Test\n\nimport java.io.File\n\nclass FileSizeWarnTest : LintTestBase(::FileSize) {\n    private val ruleId = \"$DIKTAT_RULE_SET_ID:${FileSize.NAME_ID}\"\n    private val rulesConfigListLarge: List<RulesConfig> = listOf(\n        RulesConfig(Warnings.FILE_IS_TOO_LONG.name, true,\n            mapOf(\"maxSize\" to \"5\"))\n    )\n    private val rulesConfigListSmall: List<RulesConfig> = listOf(\n        RulesConfig(Warnings.FILE_IS_TOO_LONG.name, true,\n            mapOf(\"maxSize\" to \"10\"))\n    )\n    private val rulesConfigListEmpty: List<RulesConfig> = listOf(\n        RulesConfig(Warnings.FILE_IS_TOO_LONG.name, true,\n            emptyMap())\n    )\n\n    @Test\n    @Tag(WarningNames.FILE_IS_TOO_LONG)\n    fun `file smaller then max`() {\n        val path = javaClass.classLoader.getResource(\"test/paragraph3/src/main/FileSizeLarger.kt\")\n        val file = File(path!!.file)\n        lintMethodWithFile(file.toPath(), rulesConfigList = rulesConfigListSmall)\n    }\n\n    @Test\n    @Tag(WarningNames.FILE_IS_TOO_LONG)\n    fun `file larger then max`() {\n        val path = javaClass.classLoader.getResource(\"test/paragraph3/src/main/FileSizeLarger.kt\")\n        val file = File(path!!.file)\n        val size = file\n            .readText()\n            .split(\"\\n\")\n            .size\n        lintMethodWithFile(file.toPath(),\n            DiktatError(1, 1, ruleId,\n                \"${Warnings.FILE_IS_TOO_LONG.warnText()} $size\", false),\n            rulesConfigList = rulesConfigListLarge)\n    }\n\n    @Test\n    @Tag(WarningNames.FILE_IS_TOO_LONG)\n    fun `use default values`() {\n        val path = javaClass.classLoader.getResource(\"test/paragraph3/src/main/FileSizeLarger.kt\")\n        val file = File(path!!.file)\n        lintMethodWithFile(file.toPath(), rulesConfigList = rulesConfigListEmpty)\n    }\n\n    @Test\n    @Tag(WarningNames.FILE_IS_TOO_LONG)\n    fun `file has more than 2000 lines`() {\n        val path = javaClass.classLoader.getResource(\"test/paragraph3/src/main/A/FileSize2000.kt\")\n        val file = File(path!!.file)\n        val size = generate2000lines() + 1\n        lintMethodWithFile(file.toPath(),\n            DiktatError(1, 1, ruleId,\n                \"${Warnings.FILE_IS_TOO_LONG.warnText()} $size\", false),\n            rulesConfigList = rulesConfigListLarge)\n    }\n\n    private fun generate2000lines(): Int {\n        val path = javaClass.classLoader.getResource(\"test/paragraph3/src/main/A/FileSize2000.kt\")\n        val file = File(path!!.file)\n        file.writeText(\"//hello \\n\".repeat(2000))\n        return 2000\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/test/kotlin/com/saveourtool/diktat/ruleset/chapter3/FileStructureRuleFixTest.kt",
    "content": "package com.saveourtool.diktat.ruleset.chapter3\n\nimport com.saveourtool.diktat.common.config.rules.DIKTAT_COMMON\nimport com.saveourtool.diktat.common.config.rules.RulesConfig\nimport com.saveourtool.diktat.ruleset.constants.Warnings\nimport com.saveourtool.diktat.ruleset.rules.chapter3.files.FileStructureRule\nimport com.saveourtool.diktat.util.FixTestBase\n\nimport generated.WarningNames\nimport org.junit.jupiter.api.Tag\nimport org.junit.jupiter.api.Test\n\nclass FileStructureRuleFixTest : FixTestBase(\"test/paragraph3/file_structure\", ::FileStructureRule) {\n    @Test\n    @Tag(WarningNames.FILE_INCORRECT_BLOCKS_ORDER)\n    fun `should move @file targeted annotations after header KDoc`() {\n        fixAndCompare(\"FileAnnotationExpected.kt\", \"FileAnnotationTest.kt\")\n    }\n\n    @Test\n    @Tag(WarningNames.FILE_INCORRECT_BLOCKS_ORDER)\n    fun `should move copyright comment before @file targeted annotations`() {\n        fixAndCompare(\"CopyrightCommentPositionExpected.kt\", \"CopyrightCommentPositionTest.kt\")\n    }\n\n    @Test\n    @Tag(WarningNames.FILE_INCORRECT_BLOCKS_ORDER)\n    fun `should move header kdoc before package directive`() {\n        fixAndCompare(\"HeaderKdocAfterPackageExpected.kt\", \"HeaderKdocAfterPackageTest.kt\")\n    }\n\n    @Test\n    @Tag(WarningNames.FILE_NO_BLANK_LINE_BETWEEN_BLOCKS)\n    fun `should insert blank lines between code blocks`() {\n        fixAndCompare(\"BlankLinesBetweenBlocksExpected.kt\", \"MissingBlankLinesBetweenBlocksTest.kt\")\n    }\n\n    @Test\n    @Tag(WarningNames.FILE_NO_BLANK_LINE_BETWEEN_BLOCKS)\n    fun `should remove redundant blank lines`() {\n        fixAndCompare(\"BlankLinesBetweenBlocksExpected.kt\", \"RedundantBlankLinesBetweenBlocksTest.kt\")\n    }\n\n    @Test\n    @Tag(WarningNames.FILE_UNORDERED_IMPORTS)\n    fun `should reorder imports alphabetically with saving of EOL comments`() {\n        fixAndCompare(\n            \"ReorderingImportsExpected.kt\", \"ReorderingImportsTest.kt\",\n            overrideRulesConfigList = listOf(\n                RulesConfig(\n                    Warnings.FILE_UNORDERED_IMPORTS.name, true,\n                    mapOf(\"useRecommendedImportsOrder\" to \"false\")\n                )\n            )\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.FILE_UNORDERED_IMPORTS)\n    fun `should reorder imports according to recommendation 3_1`() {\n        fixAndCompare(\n            \"ReorderingImportsRecommendedExpected.kt\", \"ReorderingImportsRecommendedTest.kt\",\n            overrideRulesConfigList = listOf(\n                RulesConfig(\n                    DIKTAT_COMMON, true,\n                    mapOf(\"domainName\" to \"com.saveourtool.diktat\")\n                ),\n                RulesConfig(\n                    Warnings.FILE_UNORDERED_IMPORTS.name, true,\n                    mapOf(\"useRecommendedImportsOrder\" to \"true\")\n                )\n            )\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.FILE_UNORDERED_IMPORTS)\n    fun `should still work with default package and some imports`() {\n        fixAndCompare(\"DefaultPackageWithImportsExpected.kt\", \"DefaultPackageWithImportsTest.kt\")\n    }\n\n    @Test\n    @Tag(WarningNames.FILE_UNORDERED_IMPORTS)\n    fun `should still work with default package and no imports`() {\n        fixAndCompare(\"NoImportNoPackageExpected.kt\", \"NoImportNoPackageTest.kt\")\n    }\n\n    @Test\n    @Tag(WarningNames.FILE_UNORDERED_IMPORTS)\n    fun `should move other comments before package node`() {\n        fixAndCompare(\"OtherCommentsExpected.kt\", \"OtherCommentsTest.kt\")\n    }\n\n    @Test\n    @Tag(WarningNames.FILE_INCORRECT_BLOCKS_ORDER)\n    fun `invalid move in kts files`() {\n        fixAndCompare(\"ScriptPackageDirectiveExpected.kts\", \"ScriptPackageDirectiveTest.kts\")\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/test/kotlin/com/saveourtool/diktat/ruleset/chapter3/FileStructureRuleTest.kt",
    "content": "package com.saveourtool.diktat.ruleset.chapter3\n\nimport com.saveourtool.diktat.common.config.rules.DIKTAT_RULE_SET_ID\nimport com.saveourtool.diktat.common.config.rules.RulesConfig\nimport com.saveourtool.diktat.ruleset.constants.Warnings\nimport com.saveourtool.diktat.ruleset.constants.Warnings.FILE_CONTAINS_ONLY_COMMENTS\nimport com.saveourtool.diktat.ruleset.constants.Warnings.FILE_INCORRECT_BLOCKS_ORDER\nimport com.saveourtool.diktat.ruleset.constants.Warnings.FILE_NO_BLANK_LINE_BETWEEN_BLOCKS\nimport com.saveourtool.diktat.ruleset.constants.Warnings.FILE_UNORDERED_IMPORTS\nimport com.saveourtool.diktat.ruleset.constants.Warnings.FILE_WILDCARD_IMPORTS\nimport com.saveourtool.diktat.ruleset.rules.chapter3.files.FileStructureRule\nimport com.saveourtool.diktat.util.LintTestBase\n\nimport com.saveourtool.diktat.api.DiktatError\nimport generated.WarningNames\nimport org.junit.jupiter.api.Disabled\nimport org.junit.jupiter.api.Tag\nimport org.junit.jupiter.api.Test\nimport org.junit.jupiter.api.io.TempDir\nimport java.nio.file.Path\n\nclass FileStructureRuleTest : LintTestBase(::FileStructureRule) {\n    private val ruleId = \"$DIKTAT_RULE_SET_ID:${FileStructureRule.NAME_ID}\"\n    private val rulesConfigListWildCardImport: List<RulesConfig> = listOf(\n        RulesConfig(FILE_WILDCARD_IMPORTS.name, true,\n            mapOf(\"allowedWildcards\" to \"com.saveourtool.diktat.*\"))\n    )\n    private val rulesConfigListWildCardImports: List<RulesConfig> = listOf(\n        RulesConfig(FILE_WILDCARD_IMPORTS.name, true,\n            mapOf(\"allowedWildcards\" to \"com.saveourtool.diktat.*, com.saveourtool.diktat.ruleset.constants.Warnings.*\"))\n    )\n    private val rulesConfigListEmptyDomainName: List<RulesConfig> = listOf(\n        RulesConfig(\"DIKTAT_COMMON\", true, mapOf(\"domainName\" to \"\"))\n    )\n\n    @Test\n    @Tag(WarningNames.FILE_CONTAINS_ONLY_COMMENTS)\n    fun `should warn if file contains only comments`() {\n        lintMethod(\n            \"\"\"\n                |package com.saveourtool.diktat.example\n                |\n                |/**\n                | * This file appears to be empty\n                | */\n                |\n                |\n                |// lorem ipsum\n            \"\"\".trimMargin(),\n            DiktatError(1, 1, ruleId, \"${FILE_CONTAINS_ONLY_COMMENTS.warnText()} file contains no code\", false)\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.FILE_INCORRECT_BLOCKS_ORDER)\n    fun `should warn if file annotations are not immediately before package directive`() {\n        lintMethod(\n            \"\"\"\n                |@file:JvmName(\"Foo\")\n                |\n                |/**\n                | * This is an example file\n                | */\n                |\n                |package com.saveourtool.diktat.example\n                |\n                |class Example { }\n            \"\"\".trimMargin(),\n            DiktatError(1, 1, ruleId, \"${FILE_INCORRECT_BLOCKS_ORDER.warnText()} @file:JvmName(\\\"Foo\\\")\", true),\n            DiktatError(3, 1, ruleId, \"${FILE_INCORRECT_BLOCKS_ORDER.warnText()} /**\", true)\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.FILE_UNORDERED_IMPORTS)\n    fun `should warn if imports are not sorted alphabetically`() {\n        lintMethod(\n            \"\"\"\n                |package com.saveourtool.diktat.example\n                |\n                |import org.junit.Test\n                |import com.saveourtool.diktat.Foo\n                |\n                |class Example {\n                |val x: Test = null\n                |val y: Foo = null\n                |}\n            \"\"\".trimMargin(),\n            DiktatError(3, 1, ruleId, \"${FILE_UNORDERED_IMPORTS.warnText()} import com.saveourtool.diktat.Foo...\", true)\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.FILE_WILDCARD_IMPORTS)\n    fun `should warn if wildcard imports are used`() {\n        lintMethod(\n            \"\"\"\n                |package com.saveourtool.diktat.example\n                |\n                |import com.saveourtool.diktat.*\n                |\n                |class Example { }\n            \"\"\".trimMargin(),\n            DiktatError(3, 1, ruleId, \"${FILE_WILDCARD_IMPORTS.warnText()} import com.saveourtool.diktat.*\", false),\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.FILE_NO_BLANK_LINE_BETWEEN_BLOCKS)\n    fun `should warn if blank lines are wrong between code blocks`() {\n        lintMethod(\n            \"\"\"\n                |/**\n                | * This is an example\n                | */\n                |@file:JvmName(\"Foo\")\n                |\n                |\n                |package com.saveourtool.diktat.example\n                |import com.saveourtool.diktat.Foo\n                |class Example{\n                |val x: Foo = null\n                |}\n            \"\"\".trimMargin(),\n            DiktatError(1, 1, ruleId, \"${FILE_NO_BLANK_LINE_BETWEEN_BLOCKS.warnText()} /**\", true),\n            DiktatError(4, 1, ruleId, \"${FILE_NO_BLANK_LINE_BETWEEN_BLOCKS.warnText()} @file:JvmName(\\\"Foo\\\")\", true),\n            DiktatError(7, 1, ruleId, \"${FILE_NO_BLANK_LINE_BETWEEN_BLOCKS.warnText()} package com.saveourtool.diktat.example\", true),\n            DiktatError(8, 1, ruleId, \"${FILE_NO_BLANK_LINE_BETWEEN_BLOCKS.warnText()} import com.saveourtool.diktat.Foo\", true)\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.FILE_WILDCARD_IMPORTS)\n    fun `wildcard imports are used but with config`() {\n        lintMethod(\n            \"\"\"\n                |package com.saveourtool.diktat.example\n                |\n                |import com.saveourtool.diktat.*\n                |\n                |class Example { }\n            \"\"\".trimMargin(), rulesConfigList = rulesConfigListWildCardImport\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.FILE_WILDCARD_IMPORTS)\n    fun `wildcard imports are used but with several imports in config`() {\n        lintMethod(\n            \"\"\"\n                |package com.saveourtool.diktat.example\n                |\n                |import com.saveourtool.diktat.*\n                |import com.saveourtool.diktat.ruleset.constants.Warnings.*\n                |\n                |class Example { }\n            \"\"\".trimMargin(), rulesConfigList = rulesConfigListWildCardImports\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.FILE_INCORRECT_BLOCKS_ORDER)\n    fun `should warn if there are other misplaced comments before package - positive example`() {\n        lintMethod(\n            \"\"\"\n                |/**\n                | * This is an example\n                | */\n                |\n                |// some notes on this file\n                |package com.saveourtool.diktat.example\n                |\n                |import com.saveourtool.diktat.Foo\n                |\n                |class Example{\n                |val x: Foo = null\n                |}\n            \"\"\".trimMargin()\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.FILE_INCORRECT_BLOCKS_ORDER)\n    fun `should warn if there are other misplaced comments before package`() {\n        lintMethod(\n            \"\"\"\n                |// some notes on this file\n                |/**\n                | * This is an example\n                | */\n                |\n                |package com.saveourtool.diktat.example\n                |\n                |import com.saveourtool.diktat.Foo\n                |\n                |class Example{\n                |val x: Foo = null\n                |}\n            \"\"\".trimMargin(),\n            DiktatError(1, 1, ruleId, \"${FILE_INCORRECT_BLOCKS_ORDER.warnText()} // some notes on this file\", true),\n            DiktatError(2, 1, ruleId, \"${FILE_INCORRECT_BLOCKS_ORDER.warnText()} /**\", true),\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.FILE_INCORRECT_BLOCKS_ORDER)\n    fun `block comment should be detected as copyright - positive example`() {\n        lintMethod(\n            \"\"\"\n                |/*\n                | * Copyright Example Inc. (c)\n                | */\n                |\n                |@file:Annotation\n                |\n                |package com.saveourtool.diktat.example\n                |\n                |import com.saveourtool.diktat.Foo\n                |\n                |class Example{\n                |val x: Foo = null\n                |}\n            \"\"\".trimMargin()\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.FILE_INCORRECT_BLOCKS_ORDER)\n    fun `block comment shouldn't be detected as copyright without keywords`() {\n        lintMethod(\n            \"\"\"\n                |/*\n                | * Just a regular block comment\n                | */\n                |@file:Annotation\n                |\n                |package com.saveourtool.diktat.example\n                |\n                |import com.saveourtool.diktat.Foo\n                |\n                |class Example{\n                |val x: Foo = null\n                |}\n            \"\"\".trimMargin(),\n            DiktatError(4, 1, ruleId, \"${FILE_INCORRECT_BLOCKS_ORDER.warnText()} @file:Annotation\", true)\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.FILE_INCORRECT_BLOCKS_ORDER)\n    fun `test with empty domain name in config`() {\n        lintMethod(\n            \"\"\"\n                |package com.saveourtool.diktat.example\n                |\n                |import com.saveourtool.diktat.Foo\n                |import com.pinterest.ktlint.core.LintError\n                |\n                |class Example{\n                |val x: LintError = null\n                |val x: Foo = null\n                |}\n            \"\"\".trimMargin(),\n            DiktatError(3, 1, ruleId, \"${FILE_UNORDERED_IMPORTS.warnText()} import com.pinterest.ktlint.core.LintError...\", true),\n            rulesConfigList = rulesConfigListEmptyDomainName\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.UNUSED_IMPORT)\n    fun `import from the package`() {\n        lintMethod(\n            \"\"\"\n                |package com.saveourtool.diktat.example\n                |\n                |import com.saveourtool.diktat.example.Foo\n                |\n                |class Example {\n                |}\n            \"\"\".trimMargin(),\n            DiktatError(1, 1, ruleId, \"${Warnings.UNUSED_IMPORT.warnText()} com.saveourtool.diktat.example.Foo - unused import\", true)\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.UNUSED_IMPORT)\n    fun `unused import`() {\n        lintMethod(\n            \"\"\"\n                |package com.saveourtool.diktat.example\n                |\n                |import com.saveourtool.diktat.Foo\n                |\n                |class Example {\n                |}\n            \"\"\".trimMargin(),\n            DiktatError(1, 1, ruleId, \"${Warnings.UNUSED_IMPORT.warnText()} com.saveourtool.diktat.Foo - unused import\", true)\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.UNUSED_IMPORT)\n    fun `used import`() {\n        lintMethod(\n            \"\"\"\n                |package com.saveourtool.diktat.example\n                |\n                |import com.saveourtool.diktat.Foo\n                |\n                |class Example {\n                |val x: Foo = null\n                |}\n            \"\"\".trimMargin(),\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.UNUSED_IMPORT)\n    fun `Operator overloading`() {\n        lintMethod(\n            \"\"\"\n                |package com.saveourtool.diktat.example\n                |\n                |import kotlin.io.path.div\n                |\n                |class Example {\n                |val pom = kotlin.io.path.createTempFile().toFile()\n                |val x = listOf(pom.parentFile.toPath() / \"src/main/kotlin/exclusion\")\n                |}\n            \"\"\".trimMargin(),\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.UNUSED_IMPORT)\n    fun `Should correctly check infix functions`() {\n        lintMethod(\n            \"\"\"\n                |package com.saveourtool.diktat.example\n                |\n                |import com.saveourtool.diktat.utils.logAndExit\n                |\n                |fun main() {\n                |\"Type is not supported yet\" logAndExit 1\n                |}\n            \"\"\".trimMargin(),\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.UNUSED_IMPORT)\n    fun `unused import to infix functions`() {\n        lintMethod(\n            \"\"\"\n                |package com.saveourtool.diktat.example\n                |\n                |import com.saveourtool.diktat.utils.logAndExit\n                |\n                |fun main() {\n                |println(\"Type is not supported yet\")\n                |}\n            \"\"\".trimMargin(),\n            DiktatError(1, 1, ruleId, \"${Warnings.UNUSED_IMPORT.warnText()} com.saveourtool.diktat.utils.logAndExit - unused import\", true)\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.UNUSED_IMPORT)\n    fun `Acute import`() {\n        lintMethod(\n            \"\"\"\n                |package com.saveourtool.diktat.example\n                |\n                |import js.externals.jquery.`${'$'}`\n                |\n                |fun main() {\n                |   `${'$'}`(\"document\").ready {}\n                |}\n            \"\"\".trimMargin(),\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.UNUSED_IMPORT)\n    fun `Ignore Imports`() {\n        lintMethod(\n            \"\"\"\n                |package com.saveourtool.diktat.example\n                |\n                |import com.example.get\n                |import com.example.invoke\n                |import com.example.set\n                |\n                |fun main() {\n                |   val a = list[1]\n                |}\n            \"\"\".trimMargin(),\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.UNUSED_IMPORT)\n    fun `check by #1`() {\n        lintMethod(\n            \"\"\"\n                |package com.saveourtool.diktat.example\n                |\n                |import com.example.get\n                |import com.example.invoke\n                |import com.example.set\n                |import kotlin.properties.Delegates\n                |\n                |fun main() {\n                |   val a by Delegates.observable()\n                |}\n            \"\"\".trimMargin(),\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.UNUSED_IMPORT)\n    fun `check by #2 should not trigger`() {\n        lintMethod(\n            \"\"\"\n                |package com.saveourtool.diktat.example\n                |\n                |import com.example.equals\n                |import com.example.get\n                |import com.example.invoke\n                |import com.example.set\n                |import org.gradle.kotlin.dsl.provideDelegate\n                |import tasks.getValue\n                |import tasks.setValue\n                |\n                |fun main() {\n                |   val a by tasks.getting  // `getValue` is used\n                |   val b by project.tasks  // `provideDelegate` is used\n                |   a != 0\n                |}\n            \"\"\".trimMargin(),\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.UNUSED_IMPORT)\n    fun `check by #3 should trigger`() {\n        lintMethod(\n            \"\"\"\n                |package com.saveourtool.diktat.example\n                |\n                |import Delegate\n                |import com.example.equals\n                |import com.example.get\n                |import com.example.invoke\n                |import com.example.set\n                |\n                |fun main() {\n                |   val a: Foo\n                |}\n            \"\"\".trimMargin(),\n            DiktatError(1, 1, ruleId, \"${Warnings.UNUSED_IMPORT.warnText()} Delegate - unused import\", true),\n            DiktatError(1, 1, ruleId, \"${Warnings.UNUSED_IMPORT.warnText()} com.example.equals - unused import\", true)\n        )\n    }\n\n    // Fixme: This test is not passing because for now we don't have type resolution\n    @Disabled\n    @Test\n    @Tag(WarningNames.UNUSED_IMPORT)\n    fun `check by #4 should trigger`() {\n        lintMethod(\n            \"\"\"\n                |package com.saveourtool.diktat.example\n                |\n                |import com.example.get\n                |import com.example.invoke\n                |import com.example.set\n                |import tasks.getValue\n                |\n                |fun main() {\n                |   val a\n                |}\n            \"\"\".trimMargin(),\n            DiktatError(1, 1, ruleId, \"${Warnings.UNUSED_IMPORT.warnText()} tasks.getValue - unused import\", true)\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.UNUSED_IMPORT)\n    fun `import in KDoc #1`() {\n        lintMethod(\n            \"\"\"\n                |import java.io.IOException\n                |\n                |interface BluetoothApi {\n                |\n                |    /**\n                |     * Send array of bytes to bluetooth output stream.\n                |     * This call is asynchronous.\n                |     *\n                |     * Note that this operation can still throw an [IOException] if the remote device silently\n                |     * closes the connection so the pipe gets broken.\n                |     *\n                |     * @param bytes data to send\n                |     * @return true if success, false if there was an error or device has been disconnected\n                |     */\n                |    fun trySend(bytes: ByteArray): Boolean\n                |}\n            \"\"\".trimMargin(),\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.UNUSED_IMPORT)\n    fun `import in KDoc #2`() {\n        lintMethod(\n            \"\"\"\n                |import java.io.IOException\n                |import java.io.IOException as IOE\n                |import java.io.UncheckedIOException\n                |import java.io.UncheckedIOException as UIOE\n                |\n                |interface BluetoothApi {\n                |    /**\n                |     * @see IOException\n                |     * @see [UncheckedIOException]\n                |     * @see IOE\n                |     * @see [UIOE]\n                |     */\n                |    fun trySend(bytes: ByteArray): Boolean\n                |}\n            \"\"\".trimMargin(),\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.UNUSED_IMPORT)\n    fun `import in KDoc #3`() {\n        lintMethod(\n            \"\"\"\n                |package com.example\n                |\n                |import com.example.Library1 as Lib1\n                |import com.example.Library1.doSmth as doSmthElse1\n                |import com.example.Library2 as Lib2\n                |import com.example.Library2.doSmth as doSmthElse2\n                |\n                |object Library1 {\n                |    fun doSmth(): Unit = TODO()\n                |}\n                |\n                |object Library2 {\n                |    fun doSmth(): Unit = TODO()\n                |}\n                |\n                |/**\n                | * @see Lib1.doSmth\n                | * @see doSmthElse1\n                | * @see [Lib2.doSmth]\n                | * @see [doSmthElse2]\n                | */\n                |class Client\n            \"\"\".trimMargin(),\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.FILE_INCORRECT_BLOCKS_ORDER)\n    fun `error in moving blocking at the first place`(@TempDir tempDir: Path) {\n        lintMethodWithFile(\n            \"\"\"\n                // Without suppressing these, version catalog usage in `plugins` is marked as an error in IntelliJ:\n                // https://youtrack.jetbrains.com/issue/KTIJ-19369\n                @file:Suppress(\"DSL_SCOPE_VIOLATION\")\n                plugins {\n                    id(libs.plugins.kotlinJvm.get().pluginId)\n                }\n            \"\"\".trimIndent(),\n            fileName = \"build.gradle.kts\",\n            tempDir = tempDir,\n            expectedLintErrors = arrayOf(DiktatError(3, 1, ruleId, \"${Warnings.FILE_INCORRECT_BLOCKS_ORDER.warnText()} @file:Suppress(\\\"DSL_SCOPE_VIOLATION\\\")\", true)),\n        )\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/test/kotlin/com/saveourtool/diktat/ruleset/chapter3/LineLengthFixTest.kt",
    "content": "package com.saveourtool.diktat.ruleset.chapter3\n\nimport com.saveourtool.diktat.common.config.rules.RulesConfig\nimport com.saveourtool.diktat.ruleset.constants.Warnings.LONG_LINE\nimport com.saveourtool.diktat.ruleset.rules.chapter3.LineLength\nimport com.saveourtool.diktat.util.FixTestBase\nimport org.junit.jupiter.api.Test\n\nclass LineLengthFixTest : FixTestBase(\"test/paragraph3/long_line\", ::LineLength) {\n    private val rulesConfigListLongLineLength: List<RulesConfig> = listOf(\n        RulesConfig(LONG_LINE.name, true,\n            mapOf(\"lineLength\" to \"175\"))\n    )\n    private val rulesConfigListDefaultLineLength: List<RulesConfig> = listOf(\n        RulesConfig(LONG_LINE.name, true,\n            mapOf(\"lineLength\" to \"120\"))\n    )\n    private val rulesConfigListLineLength: List<RulesConfig> = listOf(\n        RulesConfig(LONG_LINE.name, true,\n            mapOf(\"lineLength\" to \"50\"))\n    )\n    private val rulesConfigListShortLineLength: List<RulesConfig> = listOf(\n        RulesConfig(LONG_LINE.name, true,\n            mapOf(\"lineLength\" to \"20\"))\n    )\n    private val rulesConfigListErrorLineLength1: List<RulesConfig> = listOf(\n        RulesConfig(LONG_LINE.name, true,\n            mapOf(\"lineLength\" to \"151\"))\n    )\n\n    @Test\n    fun `should fix long comment`() {\n        fixAndCompare(\"LongLineCommentExpected.kt\", \"LongLineCommentTest.kt\", rulesConfigListLineLength)\n    }\n\n    @Test\n    fun `should fix long inline comments`() {\n        fixAndCompare(\"LongInlineCommentsExpected.kt\", \"LongInlineCommentsTest.kt\", rulesConfigListLineLength)\n    }\n\n    @Test\n    fun `should fix long comment 2`() {\n        fixAndCompare(\"LongLineCommentExpected2.kt\", \"LongLineCommentTest2.kt\", rulesConfigListDefaultLineLength)\n    }\n\n    @Test\n    fun `should fix long string template while some fix is already done`() {\n        fixAndCompare(\"LongStringTemplateExpected.kt\", \"LongStringTemplateTest.kt\", rulesConfigListDefaultLineLength)\n    }\n\n    @Test\n    fun `should fix long binary expression`() {\n        fixAndCompare(\"LongLineExpressionExpected.kt\", \"LongLineExpressionTest.kt\", rulesConfigListLineLength)\n    }\n\n    @Test\n    fun `should fix complex long binary expressions`() {\n        fixAndCompare(\"LongBinaryExpressionExpected.kt\", \"LongBinaryExpressionTest.kt\", rulesConfigListLineLength)\n    }\n\n    @Test\n    fun `should fix long function`() {\n        fixAndCompare(\"LongLineFunExpected.kt\", \"LongLineFunTest.kt\", rulesConfigListLineLength)\n    }\n\n    @Test\n    fun `should fix long right value`() {\n        fixAndCompare(\"LongLineRValueExpected.kt\", \"LongLineRValueTest.kt\", rulesConfigListLineLength)\n    }\n\n    @Test\n    fun `should fix short long right value`() {\n        fixAndCompare(\"LongShortRValueExpected.kt\", \"LongShortRValueTest.kt\", rulesConfigListShortLineLength)\n    }\n\n    @Test\n    fun `shouldn't fix`() {\n        fixAndCompare(\"LongExpressionNoFixExpected.kt\", \"LongExpressionNoFixTest.kt\", rulesConfigListShortLineLength)\n    }\n\n    @Test\n    fun `should fix annotation`() {\n        fixAndCompare(\"LongLineAnnotationExpected.kt\", \"LongLineAnnotationTest.kt\", rulesConfigListLineLength)\n    }\n\n    @Test\n    fun `fix condition in small function with long length`() {\n        fixAndCompare(\"LongConditionInSmallFunctionExpected.kt\", \"LongConditionInSmallFunctionTest.kt\", rulesConfigListLongLineLength)\n    }\n\n    @Test\n    fun `fix expression in condition`() {\n        fixAndCompare(\"LongExpressionInConditionExpected.kt\", \"LongExpressionInConditionTest.kt\", rulesConfigListLineLength)\n    }\n\n    @Test\n    fun `fix long Dot Qualified Expression`() {\n        fixAndCompare(\"LongDotQualifiedExpressionExpected.kt\", \"LongDotQualifiedExpressionTest.kt\", rulesConfigListLineLength)\n    }\n\n    @Test\n    fun `fix long value arguments list`() {\n        fixAndCompare(\"LongValueArgumentsListExpected.kt\", \"LongValueArgumentsListTest.kt\", rulesConfigListLineLength)\n    }\n\n    @Test\n    fun `fix bin expression first symbol last word`() {\n        fixAndCompare(\"LongBinaryExpressionLastWordExpected.kt\", \"LongBinaryExpressionLastWordTest.kt\", rulesConfigListErrorLineLength1)\n    }\n\n    @Test\n    fun `fix bin 1expression first symbol last word`() {\n        fixAndCompare(\"LongComplexExpressionExpected.kt\", \"LongComplexExpressionTest.kt\", rulesConfigListErrorLineLength1)\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/test/kotlin/com/saveourtool/diktat/ruleset/chapter3/LineLengthWarnTest.kt",
    "content": "@file:Suppress(\"LONG_LINE\")\n\npackage com.saveourtool.diktat.ruleset.chapter3\n\nimport com.saveourtool.diktat.common.config.rules.DIKTAT_RULE_SET_ID\nimport com.saveourtool.diktat.common.config.rules.RulesConfig\nimport com.saveourtool.diktat.ruleset.constants.Warnings.LONG_LINE\nimport com.saveourtool.diktat.ruleset.rules.chapter3.LineLength\nimport com.saveourtool.diktat.util.LintTestBase\n\nimport com.saveourtool.diktat.api.DiktatError\nimport generated.WarningNames\nimport org.junit.jupiter.api.Tag\nimport org.junit.jupiter.api.Test\n\nclass LineLengthWarnTest : LintTestBase(::LineLength) {\n    private val ruleId = \"$DIKTAT_RULE_SET_ID:${LineLength.NAME_ID}\"\n    private val rulesConfigListLineLength: List<RulesConfig> = listOf(\n        RulesConfig(LONG_LINE.name, true,\n            mapOf(\"lineLength\" to \"163\"))\n    )\n    private val shortLineLength: List<RulesConfig> = listOf(\n        RulesConfig(LONG_LINE.name, true,\n            mapOf(\"lineLength\" to \"40\"))\n    )\n    private val wrongUrl = \"dhttps://www.google.com/search?q=djfhvkdfhvkdh+gthtdj%\" +\n            \"3Bb&rlz=1C1GCEU_enRU909RU909&oq=posible+gthtdj%3Bb&aqs=chrome..\" +\n            \"69i57j0l3.2680j1j7&sourceid=chrome&ie=UTF-8\"\n    private val correctUrl = \"https://www.google.com/search?q=djfhvkdfhvkdh+gthtdj%\" +\n            \"3Bb&rlz=1C1GCEU_enRU909RU909&oq=posible+gthtdj%3Bb&aqs=chrome..\" +\n            \"69i57j0l3.2680j1j7&sourceid=chrome&ie=UTF-8\"\n\n    @Test\n    @Tag(WarningNames.LONG_LINE)\n    fun `check correct example with long URL in KDOC and long import`() {\n        lintMethod(\n            \"\"\"\n                    |package com.saveourtool.diktat.ruleset.chapter3\n                    |\n                    |import com.saveourtool.diktat.ruleset.rules.LineLength.sdfsdfsf.sdfsdfsdfsdfdghdf.gfhdf.hdstst.dh.dsgfdfgdgs.rhftheryryj.cgh\n                    |import com.saveourtool.diktat.util.lintMethod\n                    |\n                    |/**\n                    | * https://www.google.com/search?q=djfhvkdfhvkdh+gthtdj%3Bb&rlz=1C1GCEU_enRU909RU909&oq=posible+gthtdj%3Bb&aqs=chrome..69i57j0l3.2680j1j7&sourceid=chrome&ie=UTF-8\n                    | * https://www.google.com/search?q=djfhvkdfhvkdh+gthtdj%3Bb&rlz=1C1GCEU_enRU909RU909&oq=posible+gthtdj%3Bb&aqs=chrome..69i57j0l3.2680j1j7&sourceid=chrome&ie=UTF-8\n                    | * @param a\n                    |*/\n                    |\n                    |class A{\n                    |   companion object {\n                    |   }\n                    |\n                    |   fun foo() {\n                    |   }\n                    |}\n            \"\"\".trimMargin(),\n            rulesConfigList = shortLineLength\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.LONG_LINE)\n    fun `check wrong example with wrong URL in KDOC`() {\n        lintMethod(\n            \"\"\"\n                    |package com.saveourtool.diktat.ruleset.chapter3\n                    |\n                    |import com.saveourtool.diktat.ruleset.rules.chapter3.LineLength\n                    |import com.saveourtool.diktat.util.lintMethod\n                    |\n                    |/**\n                    | * https://github.com/pinterest/ktlint/blob/master/ktlint-ruleset-standard/src/main/kotlin/com/pinterest/ktlint/ruleset/standard/MaxLineLengthRule.kt\n                    | * $wrongUrl\n                    | * https://www.google.com/search?q=djfhvkdfhvkdh+gthtdj%3Bb&rlz=1C1GCEU_enRU909RU909&oq=posible+gthtdj%3Bb&aqs=chrome..69i57j0l3.2680j1j7&sourceid=chrome&ie=UTF-8\n                    | * @param a\n                    |*/\n                    |\n                    |class A{\n                    |   companion object {\n                    |   }\n                    |\n                    |   fun foo() {\n                    |   }\n                    |}\n            \"\"\".trimMargin(),\n            DiktatError(8, 1, ruleId, \"${LONG_LINE.warnText()} max line length 120, but was 163\", false)\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.LONG_LINE)\n    fun `check wrong example with wrong URL in KDOC with configuration`() {\n        lintMethod(\n            \"\"\"\n                    |package com.saveourtool.diktat.ruleset.chapter3\n                    |\n                    |import com.saveourtool.diktat.ruleset.rules.chapter3.LineLength\n                    |import com.saveourtool.diktat.util.lintMethod\n                    |\n                    |/**\n                    | * $wrongUrl\n                    | * https://www.google.com/search?q=djfhvkdfhvkdh+gthtdj%3Bb&rlz=1C1GCEU_enRU909RU909&oq=posible+gthtdj%3Bb&aqs=chrome..69i57j0l3.2680j1j7&sourceid=chrome&ie=UTF-8\n                    | * @param a\n                    |*/\n                    |\n                    |class A{\n                    |   companion object {\n                    |   }\n                    |\n                    |   fun foo() {\n                    |   }\n                    |}\n            \"\"\".trimMargin(),\n            rulesConfigList = rulesConfigListLineLength\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.LONG_LINE)\n    fun `check wrong example with long line`() {\n        lintMethod(\n            \"\"\"\n                    |package com.saveourtool.diktat.ruleset.chapter3\n                    |\n                    |import com.saveourtool.diktat.ruleset.rules.chapter3.LineLength\n                    |import com.saveourtool.diktat.util.lintMethod\n                    |\n                    |/**\n                    | * https://www.google.com/search?q=djfhvkdfhvkdh+gthtdj%3Bb&rlz=1C1GCEU_enRU909RU909&oq=posible+gthtdj%3Bb&aqs=chrome..69i57j0l3.2680j1j7&sourceid=chrome&ie=UTF-8\n                    | * https://www.google.com/search?q=djfhvkdfhvkdh+gthtdj%3Bb&rlz=1C1GCEU_enRU909RU909&oq=posible+gthtdj%3Bb&aqs=chrome..69i57j0l3.2680j1j7&sourceid=chrome&ie=UTF-8\n                    | * @param a\n                    |*/\n                    |\n                    |class A{\n                    |   companion object {\n                    |        val str = \"sdjhkjdfhkjsdhfkshfkjshkfhsdkjfhskjdfhkshdfkjsdhfkjsdhfkshdkfhsdkjfhskdjfhkjsdfhkjsdhfjksdhfkjsdhfjkhsdkjfhskdjfhksdfhskdhf\"\n                    |   }\n                    |\n                    |   fun foo() {\n                    |       val str = \"sdjhkjdfhkjsdhfkshfkjshkfhsdkjfhskjdfhkshdfkjsdhfkjsdhfkshdkfhsdkjfhskdjfhkjsdfhkjsdhfjksdhfkjsdhfjkhsdkjfhskdjfhksdfhskdhf\"\n                    |   }\n                    |}\n            \"\"\".trimMargin(),\n            DiktatError(14, 1, ruleId, \"${LONG_LINE.warnText()} max line length 120, but was 143\", true),\n            DiktatError(18, 1, ruleId, \"${LONG_LINE.warnText()} max line length 120, but was 142\", true)\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.LONG_LINE)\n    fun `check wrong example with long line but with configuration`() {\n        lintMethod(\n            \"\"\"\n                    |package com.saveourtool.diktat.ruleset.chapter3\n                    |\n                    |import com.saveourtool.diktat.ruleset.rules.chapter3.LineLength\n                    |import com.saveourtool.diktat.util.lintMethod\n                    |\n                    |/**\n                    | * This is very important URL https://www.google.com/search?q=djfhvkdfhvkdh+gthtdj%3Bb&rlz=1C1GCEU_enRU909RU909&oq=posible+gthtdj%3Bb&aqs=chrome..69i57j0l3.2680j1j7&sourceid=chrome&ie=UTF-8\n                    | * https://www.google.com/search?q=djfhvkdfhvkdh+gthtdj%3Bb&rlz=1C1GCEU_enRU909RU909&oq=posible+gthtdj%3Bb&aqs=chrome..69i57j0l3.2680j1j7&sourceid=chrome&ie=UTF-8\n                    | * $correctUrl this text can be on another line\n                    | * @param a\n                    |*/\n                    |\n                    |class A{\n                    |   companion object {\n                    |   }\n                    |\n                    |   fun foo() {\n                    |       val str = \"sdjhkjdfhkjsdhfkshfkjshkfhsdkjfhskjdfhkshdfkjsdhfkjsdhfkshdkfhsdkjfhskdjfhkjsdfhkjsdhfjksdhfkjsdhfjkhsdkjfhskdjfhksdfhskdhf\"\n                    |   }\n                    |}\n            \"\"\".trimMargin(),\n            DiktatError(9, 1, ruleId, \"${LONG_LINE.warnText()} max line length 163, but was 195\", false),\n            rulesConfigList = rulesConfigListLineLength\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.LONG_LINE)\n    fun `check correct example with long URL in KDOC in class`() {\n        lintMethod(\n            \"\"\"\n                    |package com.saveourtool.diktat.ruleset.chapter3\n                    |\n                    |import com.saveourtool.diktat.ruleset.rules.chapter3.LineLength\n                    |import com.saveourtool.diktat.util.lintMethod\n                    |\n                    |\n                    |class A {\n                    |   fun test() {\n                    |       /**\n                    |       * [link]($correctUrl)\n                    |       * [link]$correctUrl\n                    |       * https://www.google.com/search?q=djfhvkdfhvkdh+gthtdj%3Bb&rlz=1C1GCEU_enRU909RU909&oq=posible+gthtdj%3Bb&aqs=chrome..69i57j0l3.2680j1j7&sourceid=chrome&ie=UTF-8\n                    |       * https://www.google.com/search?q=djfhvkdfhvkdh+gthtdj%3Bb&rlz=1C1GCEU_enRU909RU909&oq=posible+gthtdj%3Bb&aqs=chrome..69i57j0l3.2680j1j7&sourceid=chrome&ie=UTF-8\n                    |       * @param a\n                    |       */\n                    |       println(123)\n                    |   }\n                    |}\n            \"\"\".trimMargin()\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.LONG_LINE)\n    fun `check wrong examples with long function name and properties`() {\n        lintMethod(\n            \"\"\"\n                    |package com.saveourtool.diktat.ruleset.chapter3\n                    |\n                    |import com.saveourtool.diktat.ruleset.rules.chapter3.LineLength\n                    |import com.saveourtool.diktat.util.lintMethod\n                    |\n                    |\n                    |class A {\n                    |   fun functionNameisTooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooLong() {\n                    |       val text = \"sdfkjhsdhjfgdjghdfjghdkfjghdkjghdfkghdkjhfgkjdfhgkjdfhgkjdhgfkjdfhgkjdhgkhdfkghdiulghfdilughdsdcsdcsdcs\"\n                    |       println(\"dhfgkjdhfgkjhdkfjghdkjfghdkjfhgkdfhgdkghkghdkjfhgdkghfkdjhfgkjdhfgjkdhfgkjddhfgkdhfgjkdh\")\n                    |   }\n                    |}\n            \"\"\".trimMargin(),\n            DiktatError(8, 1, ruleId, \"${LONG_LINE.warnText()} max line length 120, but was 130\", false),\n            DiktatError(9, 1, ruleId, \"${LONG_LINE.warnText()} max line length 120, but was 123\", true)\n\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.LONG_LINE)\n    fun `check annotation and fun with expr body`() {\n        lintMethod(\n            \"\"\"\n                    |@Query(value = \"ASDAASDASDASDASDASDASDASDAASDASDASDASDASDASDASDAASDASDASDASDASDASD\")\n                    |fun foo() = println(\"ASDAASDASDASDASDASDASDASDAASDASDASDASDASDASDASDAASDASDASDASDASDASD\")\n            \"\"\".trimMargin(),\n            DiktatError(1, 1, ruleId, \"${LONG_LINE.warnText()} max line length 40, but was 84\", true),\n            DiktatError(2, 1, ruleId, \"${LONG_LINE.warnText()} max line length 40, but was 89\", true),\n            rulesConfigList = shortLineLength\n        )\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/test/kotlin/com/saveourtool/diktat/ruleset/chapter3/LocalVariablesWarnTest.kt",
    "content": "package com.saveourtool.diktat.ruleset.chapter3\n\nimport com.saveourtool.diktat.common.config.rules.DIKTAT_RULE_SET_ID\nimport com.saveourtool.diktat.ruleset.constants.Warnings\nimport com.saveourtool.diktat.ruleset.rules.chapter3.identifiers.LocalVariablesRule\nimport com.saveourtool.diktat.util.LintTestBase\n\nimport com.saveourtool.diktat.api.DiktatError\nimport generated.WarningNames.LOCAL_VARIABLE_EARLY_DECLARATION\nimport org.junit.jupiter.api.Disabled\nimport org.junit.jupiter.api.Tag\nimport org.junit.jupiter.api.Test\n\n@Suppress(\"LargeClass\")\nclass LocalVariablesWarnTest : LintTestBase(::LocalVariablesRule) {\n    private val ruleId = \"$DIKTAT_RULE_SET_ID:${LocalVariablesRule.NAME_ID}\"\n\n    private fun warnMessage(name: String,\n                            declared: Int,\n                            used: Int\n    ) = \"<$name> is declared on line <$declared> and is used for the first time on line <$used>\"\n\n    @Test\n    @Tag(LOCAL_VARIABLE_EARLY_DECLARATION)\n    fun `should not check top-level and member properties`() {\n        lintMethod(\n            \"\"\"\n                    |const val foo = 0\n                    |\n                    |class Example {\n                    |    val bar = 0\n                    |}\n            \"\"\".trimMargin()\n        )\n    }\n\n    @Test\n    @Tag(LOCAL_VARIABLE_EARLY_DECLARATION)\n    fun `local variables used only in this scope - positive example`() {\n        lintMethod(\n            \"\"\"\n                    |import org.diktat.Some as test\n                    |class Example {\n                    |    fun foo() {\n                    |        val bar = 0\n                    |        baz(bar)\n                    |        println()\n                    |    }\n                    |}\n            \"\"\".trimMargin()\n        )\n    }\n\n    @Test\n    @Tag(LOCAL_VARIABLE_EARLY_DECLARATION)\n    fun `local variables used only in this scope - positive example with blank lines`() {\n        lintMethod(\n            \"\"\"\n                    |class Example {\n                    |    fun foo() {\n                    |        val bar = 0\n                    |\n                    |        baz(bar)\n                    |        println()\n                    |    }\n                    |}\n            \"\"\".trimMargin()\n        )\n    }\n\n    @Test\n    @Tag(LOCAL_VARIABLE_EARLY_DECLARATION)\n    fun `local variables used only in this scope - positive example with comments`() {\n        lintMethod(\n            \"\"\"\n                    |class Example {\n                    |    fun foo() {\n                    |        val bar = 0\n                    |        // comment\n                    |        baz(bar)\n                    |        println()\n                    |    }\n                    |}\n            \"\"\".trimMargin()\n        )\n    }\n\n    @Test\n    @Tag(LOCAL_VARIABLE_EARLY_DECLARATION)\n    fun `local var used only in this scope - positive example`() {\n        lintMethod(\n            \"\"\"\n                    |fun foo() {\n                    |    var bar: MutableList<Int>\n                    |    baz(bar)\n                    |    println()\n                    |}\n            \"\"\".trimMargin()\n        )\n    }\n\n    @Test\n    @Tag(LOCAL_VARIABLE_EARLY_DECLARATION)\n    fun `local var used only in this scope with multiline usage - positive example`() {\n        lintMethod(\n            \"\"\"\n                    |fun foo(obj: Type?) {\n                    |    var bar: MutableList<Int>\n                    |    obj\n                    |        ?.baz(bar)\n                    |    println()\n                    |}\n            \"\"\".trimMargin()\n        )\n    }\n\n    @Test\n    @Tag(LOCAL_VARIABLE_EARLY_DECLARATION)\n    fun `local variables used only in this scope`() {\n        lintMethod(\n            \"\"\"\n                    |fun foo() {\n                    |    val bar = 0\n                    |    println()\n                    |    baz(bar)\n                    |}\n            \"\"\".trimMargin(),\n            DiktatError(2, 5, ruleId, \"${Warnings.LOCAL_VARIABLE_EARLY_DECLARATION.warnText()} ${warnMessage(\"bar\", 2, 4)}\", false)\n        )\n    }\n\n    @Test\n    @Tag(LOCAL_VARIABLE_EARLY_DECLARATION)\n    fun `local variables used only in this scope - multiline declaration, positive example`() {\n        lintMethod(\n            \"\"\"\n                    |fun foo() {\n                    |    val bar = obj\n                    |        .foo()\n                    |    baz(bar)\n                    |}\n            \"\"\".trimMargin()\n        )\n    }\n\n    @Test\n    @Tag(LOCAL_VARIABLE_EARLY_DECLARATION)\n    fun `local variables used only in this scope - multiline declaration with binary expression`() {\n        lintMethod(\n            \"\"\"\n                    |fun foo() {\n                    |    val bar = 1 +\n                    |        2\n                    |    println()\n                    |    baz(bar)\n                    |}\n            \"\"\".trimMargin(),\n            DiktatError(2, 5, ruleId, \"${Warnings.LOCAL_VARIABLE_EARLY_DECLARATION.warnText()} ${warnMessage(\"bar\", 2, 5)}\", false)\n        )\n    }\n\n    @Test\n    @Tag(LOCAL_VARIABLE_EARLY_DECLARATION)\n    fun `local variables used only in this scope - multiline declaration with dot qualified property access`() {\n        lintMethod(\n            \"\"\"\n                    |fun foo() {\n                    |    val bar = \"string\"\n                    |        .size\n                    |    println()\n                    |    baz(bar)\n                    |}\n            \"\"\".trimMargin(),\n            DiktatError(2, 5, ruleId, \"${Warnings.LOCAL_VARIABLE_EARLY_DECLARATION.warnText()} ${warnMessage(\"bar\", 2, 5)}\", false)\n        )\n    }\n\n    @Test\n    @Tag(LOCAL_VARIABLE_EARLY_DECLARATION)\n    fun `local variables used only in this scope - multiline declaration with dot qualified method call`() {\n        lintMethod(\n            \"\"\"\n                    |fun foo() {\n                    |    val bar = \"string\"\n                    |        .count()\n                    |    println()\n                    |    baz(bar)\n                    |}\n            \"\"\".trimMargin(),\n            DiktatError(2, 5, ruleId, \"${Warnings.LOCAL_VARIABLE_EARLY_DECLARATION.warnText()} ${warnMessage(\"bar\", 2, 5)}\", false)\n        )\n    }\n\n    @Test\n    @Tag(LOCAL_VARIABLE_EARLY_DECLARATION)\n    @Disabled(\"Checking of variable from outer scope is not supported yet\")\n    fun `local variables defined in outer scope and used only in nested scope`() {\n        lintMethod(\n            \"\"\"\n                    |fun foo() {\n                    |    val bar = 0\n                    |    try {\n                    |        baz(bar)\n                    |    } catch (e: Exception) {\n                    |        println()\n                    |    }\n                    |}\n            \"\"\".trimMargin(),\n            DiktatError(2, 5, ruleId, \"${Warnings.LOCAL_VARIABLE_EARLY_DECLARATION.warnText()} val bar = 0\", false)\n        )\n    }\n\n    @Test\n    @Tag(LOCAL_VARIABLE_EARLY_DECLARATION)\n    fun `local variables defined in outer scope and used in several scopes - positive example`() {\n        lintMethod(\n            \"\"\"\n                    |fun foo() {\n                    |    val bar = 0\n                    |    try {\n                    |        baz(bar)\n                    |        println()\n                    |    } catch (e: Exception) {\n                    |        qux(bar)\n                    |    }\n                    |}\n            \"\"\".trimMargin()\n        )\n    }\n\n    @Test\n    @Tag(LOCAL_VARIABLE_EARLY_DECLARATION)\n    @Disabled(\"Checking of variable from outer scope is not supported yet\")\n    fun `local variables defined in outer scope and used in several scopes`() {\n        lintMethod(\n            \"\"\"\n                    |fun foo() {\n                    |    val bar = 0\n                    |    if (condition) {\n                    |        try {\n                    |            baz(bar)\n                    |            println()\n                    |        } catch (e: Exception) {\n                    |            qux(bar)\n                    |        }\n                    |    } else {\n                    |        println()\n                    |    }\n                    |}\n            \"\"\".trimMargin(),\n            DiktatError(2, 5, ruleId, \"${Warnings.LOCAL_VARIABLE_EARLY_DECLARATION.warnText()} val bar = 0\", false)\n        )\n    }\n\n    @Test\n    @Tag(LOCAL_VARIABLE_EARLY_DECLARATION)\n    fun `should not trigger on other objects fields with same name`() {\n        lintMethod(\n            \"\"\"\n                    |fun foo() {\n                    |    val size = list.size\n                    |    if (size > maxSize) {\n                    |        bar()\n                    |    }\n                    |}\n            \"\"\".trimMargin()\n        )\n    }\n\n    @Test\n    @Tag(LOCAL_VARIABLE_EARLY_DECLARATION)\n    @Disabled(\"Checking of variable from outer scope is not supported yet\")\n    fun `need to allow declaring vars outside of loops`() {\n        lintMethod(\n            \"\"\"\n                    |fun foo() {\n                    |    var offset = 0\n                    |    for (x in 1..100) {\n                    |        if (condition) {\n                    |            bar(offset)\n                    |        }\n                    |        offset += it.length\n                    |    }\n                    |}\n            \"\"\".trimMargin()\n        )\n    }\n\n    @Test\n    @Tag(LOCAL_VARIABLE_EARLY_DECLARATION)\n    fun `discovered during testing`() {\n        lintMethod(\n            \"\"\"\n                    |fun foo() {\n                    |    var offset = 0\n                    |    for (x in 1..100) {\n                    |        offset += it.length\n                    |    }\n                    |    return offset\n                    |}\n            \"\"\".trimMargin()\n        )\n    }\n\n    @Test\n    @Tag(LOCAL_VARIABLE_EARLY_DECLARATION)\n    @Disabled(\"Checking of variable from outer scope is not supported yet\")\n    fun `need to allow declaring vars outside collection methods`() {\n        lintMethod(\n            \"\"\"\n                    |fun foo() {\n                    |    var offset = 0\n                    |    list.forEach {\n                    |        if (condition) {\n                    |            bar(offset)\n                    |        }\n                    |        offset += it.length\n                    |    }\n                    |}\n            \"\"\".trimMargin()\n        )\n    }\n\n    @Test\n    @Tag(LOCAL_VARIABLE_EARLY_DECLARATION)\n    fun `should not trigger on properties with same name in different scopes`() {\n        lintMethod(\n            \"\"\"\n                    |fun foo(): Bar {\n                    |    if (condition) {\n                    |        val x = bar()\n                    |        return Bar(x)\n                    |    } else {\n                    |        val x = baz()\n                    |        return Bar(x)\n                    |    }\n                    |}\n            \"\"\".trimMargin()\n        )\n    }\n\n    @Test\n    @Tag(LOCAL_VARIABLE_EARLY_DECLARATION)\n    fun `should not trigger on properties with same name in different scopes - 2`() {\n        lintMethod(\n            \"\"\"\n                    |fun foo(): Bar {\n                    |    for (x in A) {\n                    |        val y = bar()\n                    |        qux(y)\n                    |    }\n                    |    val y = bar()\n                    |    qux(y)\n                    |}\n            \"\"\".trimMargin()\n        )\n    }\n\n    @Test\n    @Tag(LOCAL_VARIABLE_EARLY_DECLARATION)\n    fun `should not trigger when variables from outer scope are shadowed by lambda parameters`() {\n        lintMethod(\n            \"\"\"\n                    |fun foo(): Bar {\n                    |    val x = 0\n                    |    list.forEach { x ->\n                    |        println()\n                    |        bar(x)\n                    |    }\n                    |}\n            \"\"\".trimMargin()\n        )\n    }\n\n    @Test\n    @Tag(LOCAL_VARIABLE_EARLY_DECLARATION)\n    fun `should check usage inside lambdas - positive example`() {\n        lintMethod(\n            \"\"\"\n                    |fun foo(): Bar {\n                    |    val x = 0\n                    |    list.forEach {\n                    |        bar(x)\n                    |    }\n                    |}\n            \"\"\".trimMargin()\n        )\n    }\n\n    @Test\n    @Tag(LOCAL_VARIABLE_EARLY_DECLARATION)\n    fun `should check usage inside lambdas`() {\n        lintMethod(\n            \"\"\"\n                    |fun foo(): Bar {\n                    |    val x = 0\n                    |    println()\n                    |    list.forEach {\n                    |        bar(x)\n                    |    }\n                    |}\n            \"\"\".trimMargin(),\n            DiktatError(2, 5, ruleId, \"${Warnings.LOCAL_VARIABLE_EARLY_DECLARATION.warnText()} ${warnMessage(\"x\", 2, 5)}\", false)\n        )\n    }\n\n    @Test\n    @Tag(LOCAL_VARIABLE_EARLY_DECLARATION)\n    fun `should check usage inside lambdas with line break`() {\n        lintMethod(\n            \"\"\"\n                    |fun foo(): Bar {\n                    |    val x = 0\n                    |    println()\n                    |    list\n                    |        .forEach {\n                    |            bar(x)\n                    |    }\n                    |}\n            \"\"\".trimMargin(),\n            DiktatError(2, 5, ruleId, \"${Warnings.LOCAL_VARIABLE_EARLY_DECLARATION.warnText()} ${warnMessage(\"x\", 2, 6)}\", false)\n        )\n    }\n\n    @Test\n    @Tag(LOCAL_VARIABLE_EARLY_DECLARATION)\n    fun `should check properties declared inside lambda`() {\n        lintMethod(\n            \"\"\"\n                    |fun foo() {\n                    |    list.map {\n                    |        val foo = \"bar\"\n                    |        println()\n                    |        foo.baz(it)\n                    |    }\n                    |}\n            \"\"\".trimMargin(),\n            DiktatError(3, 9, ruleId, \"${Warnings.LOCAL_VARIABLE_EARLY_DECLARATION.warnText()} ${warnMessage(\"foo\", 3, 5)}\", false)\n        )\n    }\n\n    @Test\n    @Tag(LOCAL_VARIABLE_EARLY_DECLARATION)\n    fun `should not trigger when more than one variables need to be declared`() {\n        lintMethod(\n            \"\"\"\n                    |fun foo() {\n                    |    val x = 0\n                    |    val y = 1\n                    |    foo(x, y)\n                    |}\n            \"\"\".trimMargin()\n        )\n    }\n\n    @Test\n    @Tag(LOCAL_VARIABLE_EARLY_DECLARATION)\n    fun `should not raise warning if there is property not in propertyToUsages between other properties declaration`() {\n        lintMethod(\n            \"\"\"\n                    |fun foo() {\n                    |    val x = 0\n                    |    val a = -1\n                    |    val y = 1\n                    |    val z = 2\n                    |    foo(x, y, z)\n                    |}\n            \"\"\".trimMargin()\n        )\n    }\n\n    @Test\n    @Tag(LOCAL_VARIABLE_EARLY_DECLARATION)\n    fun `should not trigger on properties`() {\n        lintMethod(\n            \"\"\"\n                    |private fun checkDoc(node: ASTNode, warning: Warnings) {\n                    |    val a = 0\n                    |    val b = 1\n                    |    val c = 2\n                    |\n                    |    if (predicate(a) && predicate(b)) {\n                    |        foo(a, b, c)\n                    |    }\n                    |}\n            \"\"\".trimMargin()\n        )\n    }\n\n    @Test\n    @Tag(LOCAL_VARIABLE_EARLY_DECLARATION)\n    @Disabled(\"Constructors are not handled separately yet\")\n    fun `should check variables initialized with constructor with no parameters`() {\n        lintMethod(\n            \"\"\"\n                     |fun foo(isRequired: Boolean): Type {\n                     |    val resOption = Type()\n                     |    println()\n                     |    resOption.isRequired = isRequired\n                     |    return resOption\n                     |}\n            \"\"\".trimMargin()\n        )\n    }\n\n    @Test\n    @Tag(LOCAL_VARIABLE_EARLY_DECLARATION)\n    fun `check properties initialized with some selected methods`() {\n        lintMethod(\n            \"\"\"\n                    |fun foo() {\n                    |    val list = emptyList<Int>()\n                    |    println()\n                    |    bar(list)\n                    |}\n            \"\"\".trimMargin(),\n            DiktatError(2, 5, ruleId, \"${Warnings.LOCAL_VARIABLE_EARLY_DECLARATION.warnText()} ${warnMessage(\"list\", 2, 4)}\", false)\n        )\n    }\n\n    @Test\n    @Tag(LOCAL_VARIABLE_EARLY_DECLARATION)\n    fun `should properly detect containing scope of lambdas`() {\n        lintMethod(\n            \"\"\"\n                    |fun foo() {\n                    |    val res = mutableListOf<Type>()\n                    |    Foo.bar(\n                    |            Foo.baz(\n                    |                    cb = { e, _ -> res.add(e) }\n                    |            )\n                    |    )\n                    |    Assertions.assertThat(res).isEmpty()\n                    |}\n            \"\"\".trimMargin()\n        )\n    }\n\n    @Test\n    @Tag(LOCAL_VARIABLE_EARLY_DECLARATION)\n    fun `should not trigger when there is a property in a class and same variable name in function and lambda`() {\n        lintMethod(\n            \"\"\"\n                    |class Example {\n                    |    val a = \"a1\"\n                    |    fun foo() {\n                    |        val a = \"a2\"\n                    |        listOf<String>().forEach { a -> println(a) }\n                    |    }\n                    |}\n            \"\"\".trimMargin()\n        )\n    }\n\n    @Test\n    @Tag(LOCAL_VARIABLE_EARLY_DECLARATION)\n    fun `should not trigger on triple quoted strings`() {\n        lintMethod(\n            \"\"\"\n                    |class Example {\n                    |    fun some() {\n                    |       val code = ${\"\\\"\\\"\\\"\"}\n                    |                 class Some {\n                    |                   fun for() : String {\n                    |                   }\n                    |                 }\n                    |               ${\"\\\"\\\"\\\"\"}.trimIndent()\n                    |       bar(code)\n                    |    }\n                    |}\n            \"\"\".trimMargin()\n        )\n    }\n\n    @Test\n    @Tag(LOCAL_VARIABLE_EARLY_DECLARATION)\n    fun `should not trigger on space after last val`() {\n        lintMethod(\n            \"\"\"\n                    |    private fun collectAllExtensionFunctions(node: ASTNode): SimilarSignatures {\n                    |       val extensionFunctionList = node.findAllNodesWithSpecificType(FUN).filter { it.hasChildOfType(TYPE_REFERENCE) && it.hasChildOfType(DOT) }\n                    |       val distinctFunctionSignatures = mutableMapOf<FunctionSignature, ASTNode>()  // maps function signatures on node it is used by\n                    |       val extensionFunctionsPairs = mutableListOf<Pair<ExtensionFunction, ExtensionFunction>>()  // pairs extension functions with same signature\n                    |\n                    |       extensionFunctionList.forEach { func ->\n                    |           if (distinctFunctionSignatures.contains(signature)) {\n                    |               val secondFuncClassName = distinctFunctionSignatures[signature]!!.findChildBefore(DOT, TYPE_REFERENCE)!!.text\n                    |               extensionFunctionsPairs.add(Pair(\n                    |               ExtensionFunction(secondFuncClassName, signature, distinctFunctionSignatures[signature]!!),\n                    |               ExtensionFunction(className, signature, func)))\n                    |           } else {\n                    |               distinctFunctionSignatures[signature] = func\n                    |           }\n                    |       }\n                    |       return extensionFunctionsPairs\n                    |   }\n            \"\"\".trimMargin()\n        )\n    }\n\n    @Test\n    @Tag(LOCAL_VARIABLE_EARLY_DECLARATION)\n    fun `should not trigger on var nodes which have initializer`() {\n        lintMethod(\n            \"\"\"\n                    |    private fun collectAllExtensionFunctions(astNode: ASTNode): SimilarSignatures {\n                    |       var text = \"\"\n                    |       var node = astNode\n                    |       var prevNode: ASTNode\n                    |       do {\n                    |           prevNode = node\n                    |           node = node.treeParent\n                    |           if (node.elementType == ElementType.PARENTHESIZED) {\n                    |               text += getTextFromParenthesized(node)\n                    |           }\n                    |       } while (node.elementType != BINARY_EXPRESSION)\n                    |   }\n            \"\"\".trimMargin()\n        )\n    }\n\n    @Test\n    @Tag(LOCAL_VARIABLE_EARLY_DECLARATION)\n    fun `should skip comments`() {\n        lintMethod(\n            \"\"\"\n                    |    private fun collectAllExtensionFunctions(astNode: ASTNode): SimilarSignatures {\n                    |       var copyrightComment = \"\"\n                    |       var headerKdoc = listOf()\n                    |       // Annotations with target`file` can only be placed before `package` directive.\n                    |       var fileAnnotations = node.findChildByType(FILE_ANNOTATION_LIST)\n                    |       // We also collect all other elements that are placed on top of the file.\n                    |       // These may be other comments, so we just place them before the code starts.\n                    |       val otherNodesBeforeCode = firstCodeNode.siblings(forward = false)\n                    |           .filterNot {\n                    |               it.isWhiteSpace() ||\n                    |                   it == copyrightComment || it == headerKdoc || it == fileAnnotations\n                    |           }\n                    |           .toList()\n                    |           .reversed()\n                    |   }\n            \"\"\".trimMargin()\n        )\n    }\n\n    @Test\n    @Tag(LOCAL_VARIABLE_EARLY_DECLARATION)\n    fun `should skip val nodes between considered nodes`() {\n        lintMethod(\n            \"\"\"\n                    |    private fun collectAllExtensionFunctions(astNode: ASTNode): SimilarSignatures {\n                    |       val text = \"\"\n                    |       val node = astNode\n                    |       var prevNode: ASTNode\n                    |       some(text, node, prevNode)\n                    |   }\n            \"\"\".trimMargin()\n        )\n    }\n\n    @Test\n    @Tag(LOCAL_VARIABLE_EARLY_DECLARATION)\n    fun `should skip val and var nodes between considered nodes`() {\n        // Only text goes to propertyToUsages here\n        lintMethod(\n            \"\"\"\n                    |    private fun collectAllExtensionFunctions(astNode: ASTNode): SimilarSignatures {\n                    |       val text = \"\"\n                    |       val node = astNode\n                    |       val prevNode: ASTNode = astNode\n                    |       some(text, node, prevNode)\n                    |   }\n            \"\"\".trimMargin()\n        )\n    }\n\n    @Test\n    @Tag(LOCAL_VARIABLE_EARLY_DECLARATION)\n    fun `shouldn't fail on double invocations`() {\n        lintMethod(\n            \"\"\"\n                |fun bar() {\n                |    val x = foo()()\n                |    val x = foo()()()\n                |}\n            \"\"\".trimMargin()\n        )\n    }\n\n    @Test\n    @Tag(LOCAL_VARIABLE_EARLY_DECLARATION)\n    fun `shouldn't fail on semicolon`() {\n        lintMethod(\n            \"\"\"\n                |fun bar() {\n                |    var a = 0;\n                |    a++\n                |}\n            \"\"\".trimMargin()\n        )\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/test/kotlin/com/saveourtool/diktat/ruleset/chapter3/LongNumericalValuesSeparatedFixTest.kt",
    "content": "package com.saveourtool.diktat.ruleset.chapter3\n\nimport com.saveourtool.diktat.common.config.rules.RulesConfig\nimport com.saveourtool.diktat.ruleset.constants.Warnings\nimport com.saveourtool.diktat.ruleset.rules.chapter3.LongNumericalValuesSeparatedRule\nimport com.saveourtool.diktat.util.FixTestBase\n\nimport generated.WarningNames.LONG_NUMERICAL_VALUES_SEPARATED\nimport org.junit.jupiter.api.Tag\nimport org.junit.jupiter.api.Test\n\nclass LongNumericalValuesSeparatedFixTest : FixTestBase(\"test/paragraph3/long_numbers\", ::LongNumericalValuesSeparatedRule) {\n    private val rulesConfig: List<RulesConfig> = listOf(\n        RulesConfig(Warnings.LONG_NUMERICAL_VALUES_SEPARATED.name, true,\n            mapOf(\"maxNumberLength\" to \"5\", \"maxBlockLength\" to \"3\"))\n    )\n\n    @Test\n    @Tag(LONG_NUMERICAL_VALUES_SEPARATED)\n    fun `should add delimiters`() {\n        fixAndCompare(\"LongNumericalValuesExpected.kt\", \"LongNumericalValuesTest.kt\", rulesConfig)\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/test/kotlin/com/saveourtool/diktat/ruleset/chapter3/LongNumericalValuesSeparatedWarnTest.kt",
    "content": "package com.saveourtool.diktat.ruleset.chapter3\n\nimport com.saveourtool.diktat.common.config.rules.DIKTAT_RULE_SET_ID\nimport com.saveourtool.diktat.common.config.rules.RulesConfig\nimport com.saveourtool.diktat.ruleset.constants.Warnings\nimport com.saveourtool.diktat.ruleset.rules.chapter3.LongNumericalValuesSeparatedRule\nimport com.saveourtool.diktat.util.LintTestBase\n\nimport com.saveourtool.diktat.api.DiktatError\nimport generated.WarningNames.LONG_NUMERICAL_VALUES_SEPARATED\nimport org.junit.jupiter.api.Tag\nimport org.junit.jupiter.api.Test\n\nclass LongNumericalValuesSeparatedWarnTest : LintTestBase(::LongNumericalValuesSeparatedRule) {\n    private val ruleId = \"$DIKTAT_RULE_SET_ID:${LongNumericalValuesSeparatedRule.NAME_ID}\"\n    private val rulesConfig: List<RulesConfig> = listOf(\n        RulesConfig(Warnings.LONG_NUMERICAL_VALUES_SEPARATED.name, true,\n            mapOf(\"maxNumberLength\" to \"2\"))\n    )\n\n    @Test\n    @Tag(LONG_NUMERICAL_VALUES_SEPARATED)\n    fun `check properties test bad`() {\n        lintMethod(\n            \"\"\"\n                    |fun foo() {\n                    |   val oneMillion = 100000000000\n                    |   val creditCardNumber = 1234567890123456L\n                    |   val socialSecurityNumber = 999999999L\n                    |   val hexBytes = 0xFFECDE5E\n                    |   val hexBytes2 = 0xF\n                    |   val bytes = 0b110100110_01101001_10010100_10010010\n                    |   val flo = 192.312341341344355345\n                    |   val flo2 = 192.31234134134435_5345\n                    |   val hundred = 100\n                    |}\n            \"\"\".trimMargin(),\n            DiktatError(2, 21, ruleId, \"${Warnings.LONG_NUMERICAL_VALUES_SEPARATED.warnText()} 100000000000\", true),\n            DiktatError(3, 27, ruleId, \"${Warnings.LONG_NUMERICAL_VALUES_SEPARATED.warnText()} 1234567890123456L\", true),\n            DiktatError(4, 31, ruleId, \"${Warnings.LONG_NUMERICAL_VALUES_SEPARATED.warnText()} 999999999L\", true),\n            DiktatError(5, 19, ruleId, \"${Warnings.LONG_NUMERICAL_VALUES_SEPARATED.warnText()} 0xFFECDE5E\", true),\n            DiktatError(7, 16, ruleId, \"${Warnings.LONG_NUMERICAL_VALUES_SEPARATED.warnText()} this block is too long 110100110\", false),\n            DiktatError(7, 16, ruleId, \"${Warnings.LONG_NUMERICAL_VALUES_SEPARATED.warnText()} this block is too long 01101001\", false),\n            DiktatError(7, 16, ruleId, \"${Warnings.LONG_NUMERICAL_VALUES_SEPARATED.warnText()} this block is too long 10010100\", false),\n            DiktatError(7, 16, ruleId, \"${Warnings.LONG_NUMERICAL_VALUES_SEPARATED.warnText()} this block is too long 10010010\", false),\n            DiktatError(8, 14, ruleId, \"${Warnings.LONG_NUMERICAL_VALUES_SEPARATED.warnText()} 192.312341341344355345\", true),\n            DiktatError(9, 15, ruleId, \"${Warnings.LONG_NUMERICAL_VALUES_SEPARATED.warnText()} this block is too long 31234134134435\", false),\n            DiktatError(9, 15, ruleId, \"${Warnings.LONG_NUMERICAL_VALUES_SEPARATED.warnText()} this block is too long 5345\", false)\n\n        )\n    }\n\n    @Test\n    @Tag(LONG_NUMERICAL_VALUES_SEPARATED)\n    fun `check properties test good`() {\n        lintMethod(\n            \"\"\"\n                    |fun foo() {\n                    |   val oneMillion = 1_000_000_000_000\n                    |   val creditCardNumber = 1_234_567_890_123_456L\n                    |   val socialSecurityNumber = 999_999_999L\n                    |   val hexBytes = 0xFF_EC_DE_5E\n                    |   val bytes = 0b11_010_010_011_010_011_001_010_010_010_010\n                    |   val flo = 192.312_341_341_345\n                    |   val ten = 10\n                    |}\n            \"\"\".trimMargin()\n        )\n    }\n\n    @Test\n    @Tag(LONG_NUMERICAL_VALUES_SEPARATED)\n    fun `check properties test bad 2`() {\n        lintMethod(\n            \"\"\"\n                    |fun foo() {\n                    |   val oneMillion = 100\n                    |   val creditCardNumber = 1234566L\n                    |   val socialSecurityNumber = 999L\n                    |   val hexBytes = 0xFFE\n                    |   val bytes = 0b110100\n                    |   val flo = 192.312\n                    |}\n            \"\"\".trimMargin(),\n            DiktatError(2, 21, ruleId, \"${Warnings.LONG_NUMERICAL_VALUES_SEPARATED.warnText()} 100\", true),\n            DiktatError(3, 27, ruleId, \"${Warnings.LONG_NUMERICAL_VALUES_SEPARATED.warnText()} 1234566L\", true),\n            DiktatError(4, 31, ruleId, \"${Warnings.LONG_NUMERICAL_VALUES_SEPARATED.warnText()} 999L\", true),\n            DiktatError(5, 19, ruleId, \"${Warnings.LONG_NUMERICAL_VALUES_SEPARATED.warnText()} 0xFFE\", true),\n            DiktatError(6, 16, ruleId, \"${Warnings.LONG_NUMERICAL_VALUES_SEPARATED.warnText()} 0b110100\", true),\n            DiktatError(7, 14, ruleId, \"${Warnings.LONG_NUMERICAL_VALUES_SEPARATED.warnText()} 192.312\", true),\n            rulesConfigList = rulesConfig\n        )\n    }\n\n    @Test\n    @Tag(LONG_NUMERICAL_VALUES_SEPARATED)\n    fun `check func params test good`() {\n        lintMethod(\n            \"\"\"\n                    |fun foo(val one = 100_000_000) {\n                    |\n                    |}\n            \"\"\".trimMargin()\n        )\n    }\n\n    @Test\n    @Tag(LONG_NUMERICAL_VALUES_SEPARATED)\n    fun `check func params test bad`() {\n        lintMethod(\n            \"\"\"\n                    |fun foo(val one = 100000000) {\n                    |\n                    |}\n            \"\"\".trimMargin(),\n            DiktatError(1, 19, ruleId, \"${Warnings.LONG_NUMERICAL_VALUES_SEPARATED.warnText()} 100000000\", true)\n        )\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/test/kotlin/com/saveourtool/diktat/ruleset/chapter3/MagicNumberRuleWarnTest.kt",
    "content": "package com.saveourtool.diktat.ruleset.chapter3\n\nimport com.saveourtool.diktat.api.DiktatError\nimport com.saveourtool.diktat.common.config.rules.DIKTAT_RULE_SET_ID\nimport com.saveourtool.diktat.common.config.rules.RulesConfig\nimport com.saveourtool.diktat.ruleset.constants.Warnings.MAGIC_NUMBER\nimport com.saveourtool.diktat.ruleset.rules.chapter3.MagicNumberRule\nimport com.saveourtool.diktat.util.LintTestBase\nimport generated.WarningNames\nimport org.junit.jupiter.api.Tag\nimport org.junit.jupiter.api.Test\n\nclass MagicNumberRuleWarnTest : LintTestBase(::MagicNumberRule) {\n    private val ruleId = \"$DIKTAT_RULE_SET_ID:${MagicNumberRule.NAME_ID}\"\n    private val rulesConfigIgnoreNone: List<RulesConfig> = listOf(\n        RulesConfig(\n            MAGIC_NUMBER.name, true,\n            mapOf(\n                \"ignoreHashCodeFunction\" to \"false\",\n                \"ignorePropertyDeclaration\" to \"false\",\n                \"ignoreLocalVariableDeclaration\" to \"false\",\n                \"ignoreValueParameter\" to \"false\",\n                \"ignoreConstantDeclaration\" to \"false\",\n                \"ignoreCompanionObjectPropertyDeclaration\" to \"false\",\n                \"ignoreEnums\" to \"false\",\n                \"ignoreRanges\" to \"false\",\n                \"ignoreExtensionFunctions\" to \"false\",\n                \"ignorePairsCreatedUsingTo\" to \"false\"))\n    )\n    private val rulesConfigIgnoreNumbers: List<RulesConfig> = listOf(\n        RulesConfig(\n            MAGIC_NUMBER.name, true,\n            mapOf(\n                \"ignoreNumbers\" to \"50,-240, 128L, -3.5f, 4, 11UL\",\n                \"ignoreHashCodeFunction\" to \"false\",\n                \"ignorePropertyDeclaration\" to \"false\",\n                \"ignoreLocalVariableDeclaration\" to \"false\",\n                \"ignoreValueParameter\" to \"false\",\n                \"ignoreConstantDeclaration\" to \"false\",\n                \"ignoreCompanionObjectPropertyDeclaration\" to \"false\",\n                \"ignoreEnums\" to \"false\",\n                \"ignoreRanges\" to \"false\",\n                \"ignoreExtensionFunctions\" to \"false\",\n                \"ignorePairsCreatedUsingTo\" to \"false\"))\n    )\n    private val rulesConfigIgnoreHashCodeFunction: List<RulesConfig> = listOf(\n        RulesConfig(\n            MAGIC_NUMBER.name, true,\n            mapOf(\n                \"ignoreHashCodeFunction\" to \"true\",\n                \"ignorePropertyDeclaration\" to \"false\",\n                \"ignoreLocalVariableDeclaration\" to \"false\",\n                \"ignoreValueParameter\" to \"false\",\n                \"ignoreConstantDeclaration\" to \"false\",\n                \"ignoreCompanionObjectPropertyDeclaration\" to \"false\",\n                \"ignoreEnums\" to \"false\",\n                \"ignoreRanges\" to \"false\",\n                \"ignoreExtensionFunctions\" to \"false\",\n                \"ignorePairsCreatedUsingTo\" to \"false\"))\n    )\n    private val rulesConfigIgnorePropertyDeclaration: List<RulesConfig> = listOf(\n        RulesConfig(\n            MAGIC_NUMBER.name, true,\n            mapOf(\n                \"ignoreHashCodeFunction\" to \"false\",\n                \"ignorePropertyDeclaration\" to \"true\",\n                \"ignoreLocalVariableDeclaration\" to \"false\",\n                \"ignoreValueParameter\" to \"false\",\n                \"ignoreConstantDeclaration\" to \"false\",\n                \"ignoreCompanionObjectPropertyDeclaration\" to \"false\",\n                \"ignoreEnums\" to \"false\",\n                \"ignoreRanges\" to \"false\",\n                \"ignoreExtensionFunctions\" to \"false\",\n                \"ignorePairsCreatedUsingTo\" to \"false\"))\n    )\n    private val rulesConfigIgnoreLocalVariableDeclaration: List<RulesConfig> = listOf(\n        RulesConfig(\n            MAGIC_NUMBER.name, true,\n            mapOf(\n                \"ignoreHashCodeFunction\" to \"false\",\n                \"ignorePropertyDeclaration\" to \"false\",\n                \"ignoreLocalVariableDeclaration\" to \"true\",\n                \"ignoreValueParameter\" to \"false\",\n                \"ignoreConstantDeclaration\" to \"false\",\n                \"ignoreCompanionObjectPropertyDeclaration\" to \"false\",\n                \"ignoreEnums\" to \"false\",\n                \"ignoreRanges\" to \"false\",\n                \"ignoreExtensionFunctions\" to \"false\",\n                \"ignorePairsCreatedUsingTo\" to \"false\"))\n    )\n    private val rulesConfigIgnoreValueParameter: List<RulesConfig> = listOf(\n        RulesConfig(\n            MAGIC_NUMBER.name, true,\n            mapOf(\n                \"ignoreHashCodeFunction\" to \"false\",\n                \"ignorePropertyDeclaration\" to \"false\",\n                \"ignoreLocalVariableDeclaration\" to \"false\",\n                \"ignoreValueParameter\" to \"true\",\n                \"ignoreConstantDeclaration\" to \"false\",\n                \"ignoreCompanionObjectPropertyDeclaration\" to \"false\",\n                \"ignoreEnums\" to \"false\",\n                \"ignoreRanges\" to \"false\",\n                \"ignoreExtensionFunctions\" to \"false\",\n                \"ignorePairsCreatedUsingTo\" to \"false\"))\n    )\n    private val rulesConfigIgnoreConstantDeclaration: List<RulesConfig> = listOf(\n        RulesConfig(\n            MAGIC_NUMBER.name, true,\n            mapOf(\n                \"ignoreHashCodeFunction\" to \"false\",\n                \"ignorePropertyDeclaration\" to \"false\",\n                \"ignoreLocalVariableDeclaration\" to \"false\",\n                \"ignoreValueParameter\" to \"false\",\n                \"ignoreConstantDeclaration\" to \"true\",\n                \"ignoreCompanionObjectPropertyDeclaration\" to \"false\",\n                \"ignoreEnums\" to \"false\",\n                \"ignoreRanges\" to \"false\",\n                \"ignoreExtensionFunctions\" to \"false\",\n                \"ignorePairsCreatedUsingTo\" to \"false\"))\n    )\n    private val rulesConfigIgnoreCompanionObjectPropertyDeclaration: List<RulesConfig> = listOf(\n        RulesConfig(\n            MAGIC_NUMBER.name, true,\n            mapOf(\n                \"ignoreHashCodeFunction\" to \"false\",\n                \"ignorePropertyDeclaration\" to \"false\",\n                \"ignoreLocalVariableDeclaration\" to \"false\",\n                \"ignoreValueParameter\" to \"false\",\n                \"ignoreConstantDeclaration\" to \"false\",\n                \"ignoreCompanionObjectPropertyDeclaration\" to \"true\",\n                \"ignoreEnums\" to \"false\",\n                \"ignoreRanges\" to \"false\",\n                \"ignoreExtensionFunctions\" to \"false\",\n                \"ignorePairsCreatedUsingTo\" to \"false\"))\n    )\n    private val rulesConfigIgnoreEnums: List<RulesConfig> = listOf(\n        RulesConfig(\n            MAGIC_NUMBER.name, true,\n            mapOf(\n                \"ignoreHashCodeFunction\" to \"false\",\n                \"ignorePropertyDeclaration\" to \"false\",\n                \"ignoreLocalVariableDeclaration\" to \"false\",\n                \"ignoreValueParameter\" to \"false\",\n                \"ignoreConstantDeclaration\" to \"false\",\n                \"ignoreCompanionObjectPropertyDeclaration\" to \"false\",\n                \"ignoreEnums\" to \"true\",\n                \"ignoreRanges\" to \"false\",\n                \"ignoreExtensionFunctions\" to \"false\",\n                \"ignorePairsCreatedUsingTo\" to \"false\"))\n    )\n    private val rulesConfigIgnoreRanges: List<RulesConfig> = listOf(\n        RulesConfig(\n            MAGIC_NUMBER.name, true,\n            mapOf(\n                \"ignoreHashCodeFunction\" to \"false\",\n                \"ignorePropertyDeclaration\" to \"false\",\n                \"ignoreLocalVariableDeclaration\" to \"false\",\n                \"ignoreValueParameter\" to \"false\",\n                \"ignoreConstantDeclaration\" to \"false\",\n                \"ignoreCompanionObjectPropertyDeclaration\" to \"false\",\n                \"ignoreEnums\" to \"false\",\n                \"ignoreRanges\" to \"true\",\n                \"ignoreExtensionFunctions\" to \"false\",\n                \"ignorePairsCreatedUsingTo\" to \"false\"))\n    )\n    private val rulesConfigIgnoreExtensionFunctions: List<RulesConfig> = listOf(\n        RulesConfig(\n            MAGIC_NUMBER.name, true,\n            mapOf(\n                \"ignoreHashCodeFunction\" to \"false\",\n                \"ignorePropertyDeclaration\" to \"false\",\n                \"ignoreLocalVariableDeclaration\" to \"false\",\n                \"ignoreValueParameter\" to \"false\",\n                \"ignoreConstantDeclaration\" to \"false\",\n                \"ignoreCompanionObjectPropertyDeclaration\" to \"false\",\n                \"ignoreEnums\" to \"false\",\n                \"ignoreRanges\" to \"false\",\n                \"ignoreExtensionFunctions\" to \"true\",\n                \"ignorePairsCreatedUsingTo\" to \"false\"))\n    )\n    private val rulesConfigIgnorePairsCreatedUsingTo: List<RulesConfig> = listOf(\n        RulesConfig(\n            MAGIC_NUMBER.name, true,\n            mapOf(\n                \"ignoreHashCodeFunction\" to \"false\",\n                \"ignorePropertyDeclaration\" to \"false\",\n                \"ignoreLocalVariableDeclaration\" to \"false\",\n                \"ignoreValueParameter\" to \"false\",\n                \"ignoreConstantDeclaration\" to \"false\",\n                \"ignoreCompanionObjectPropertyDeclaration\" to \"false\",\n                \"ignoreEnums\" to \"false\",\n                \"ignoreRanges\" to \"false\",\n                \"ignoreExtensionFunctions\" to \"false\",\n                \"ignorePairsCreatedUsingTo\" to \"true\"))\n    )\n\n    @Test\n    @Tag(WarningNames.MAGIC_NUMBER)\n    @Suppress(\"LongMethod\")\n    fun `check all`() {\n        lintMethod(\n            \"\"\"\n                |fun f1oo() {\n                |   val a: Byte = 4\n                |   val b = 128L\n                |   val e = 3.4f\n                |   val g = 4/3\n                |   val h = 0U\n                |   val r = 1UL\n                |   val f = \"qwe\\$\\{12\\}hhe\"\n                |}\n                |\n                |@Override\n                |fun hashCode(): Int {\n                |   return 32\n                |}\n                |\n                |val abc = 32\n                |var abc2 = 32\n                |\n                |fun foo() {\n                |   val a = 3\n                |   var a2 = 3\n                |}\n                |\n                |class TomlDecoder(\n                |    val elementsCount: Int = 100,\n                |    var elementsCount2: Int = 100\n                |)\n                |\n                |fun TomlDecoder(elementsCount: Int = 100) {}\n                |\n                |const val topLevel = 31\n                |\n                |class A {\n                |   companion object {\n                |       val b = 3\n                |       var b2 = 4\n                |   }\n                |}\n                |\n                |enum class A(b:Int) {\n                |   A(3),\n                |   B(4),\n                |   C(5),\n                |}\n                |\n                |val tagLengthRange = 3..15\n                |var tagLengthRange2 = 3..15\n                |\n                |fun Int.foo() = 3\n                |\n                |val fg = abc to 3\n                |var fg2 = abc to 4\n            \"\"\".trimMargin(),\n            DiktatError(2, 18, ruleId, \"${MAGIC_NUMBER.warnText()} 4\", false),\n            DiktatError(3, 12, ruleId, \"${MAGIC_NUMBER.warnText()} 128L\", false),\n            DiktatError(4, 12, ruleId, \"${MAGIC_NUMBER.warnText()} 3.4f\", false),\n            DiktatError(5, 12, ruleId, \"${MAGIC_NUMBER.warnText()} 4\", false),\n            DiktatError(5, 14, ruleId, \"${MAGIC_NUMBER.warnText()} 3\", false),\n            DiktatError(13, 11, ruleId, \"${MAGIC_NUMBER.warnText()} 32\", false),\n            DiktatError(16, 11, ruleId, \"${MAGIC_NUMBER.warnText()} 32\", false),\n            DiktatError(17, 12, ruleId, \"${MAGIC_NUMBER.warnText()} 32\", false),\n            DiktatError(20, 12, ruleId, \"${MAGIC_NUMBER.warnText()} 3\", false),\n            DiktatError(21, 13, ruleId, \"${MAGIC_NUMBER.warnText()} 3\", false),\n            DiktatError(25, 30, ruleId, \"${MAGIC_NUMBER.warnText()} 100\", false),\n            DiktatError(26, 31, ruleId, \"${MAGIC_NUMBER.warnText()} 100\", false),\n            DiktatError(29, 38, ruleId, \"${MAGIC_NUMBER.warnText()} 100\", false),\n            DiktatError(31, 22, ruleId, \"${MAGIC_NUMBER.warnText()} 31\", false),\n            DiktatError(35, 16, ruleId, \"${MAGIC_NUMBER.warnText()} 3\", false),\n            DiktatError(36, 17, ruleId, \"${MAGIC_NUMBER.warnText()} 4\", false),\n            DiktatError(41, 6, ruleId, \"${MAGIC_NUMBER.warnText()} 3\", false),\n            DiktatError(42, 6, ruleId, \"${MAGIC_NUMBER.warnText()} 4\", false),\n            DiktatError(43, 6, ruleId, \"${MAGIC_NUMBER.warnText()} 5\", false),\n            DiktatError(46, 22, ruleId, \"${MAGIC_NUMBER.warnText()} 3\", false),\n            DiktatError(46, 25, ruleId, \"${MAGIC_NUMBER.warnText()} 15\", false),\n            DiktatError(47, 23, ruleId, \"${MAGIC_NUMBER.warnText()} 3\", false),\n            DiktatError(47, 26, ruleId, \"${MAGIC_NUMBER.warnText()} 15\", false),\n            DiktatError(49, 17, ruleId, \"${MAGIC_NUMBER.warnText()} 3\", false),\n            DiktatError(51, 17, ruleId, \"${MAGIC_NUMBER.warnText()} 3\", false),\n            DiktatError(52, 18, ruleId, \"${MAGIC_NUMBER.warnText()} 4\", false),\n            rulesConfigList = rulesConfigIgnoreNone\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.MAGIC_NUMBER)\n    fun `check ignore numbers`() {\n        lintMethod(\n            \"\"\"\n                |fun f1oo() {\n                |   val m = -1\n                |   var m2 = -1\n                |   val a: Byte = 4\n                |   var a2: Byte = 4\n                |   val b = 0xff\n                |   var b2 = 0xff\n                |}\n                |\n                |enum class A(b:Int) {\n                |   A(-240),\n                |   B(50),\n                |   C(3),\n                |}\n            \"\"\".trimMargin(),\n            DiktatError(2, 13, ruleId, \"${MAGIC_NUMBER.warnText()} -1\", false),\n            DiktatError(3, 14, ruleId, \"${MAGIC_NUMBER.warnText()} -1\", false),\n            DiktatError(6, 12, ruleId, \"${MAGIC_NUMBER.warnText()} 0xff\", false),\n            DiktatError(7, 13, ruleId, \"${MAGIC_NUMBER.warnText()} 0xff\", false),\n            DiktatError(13, 6, ruleId, \"${MAGIC_NUMBER.warnText()} 3\", false),\n            rulesConfigList = rulesConfigIgnoreNumbers\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.MAGIC_NUMBER)\n    fun `check ignore hash code function`() {\n        lintMethod(\n            \"\"\"\n                |@Override\n                |fun hashCode(): Int {\n                |   return 32\n                |}\n            \"\"\".trimMargin(),\n            rulesConfigList = rulesConfigIgnoreHashCodeFunction\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.MAGIC_NUMBER)\n    fun `check ignore property declaration`() {\n        lintMethod(\n            \"\"\"\n                |val abc = 32\n                |var abc2 = 32\n            \"\"\".trimMargin(),\n            rulesConfigList = rulesConfigIgnorePropertyDeclaration\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.MAGIC_NUMBER)\n    fun `check ignore local variable declaration`() {\n        lintMethod(\n            \"\"\"\n                |fun foo() {\n                |   val a = 3\n                |   var a2 = 3\n                |}\n            \"\"\".trimMargin(),\n            rulesConfigList = rulesConfigIgnoreLocalVariableDeclaration\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.MAGIC_NUMBER)\n    fun `check ignore value parameter`() {\n        lintMethod(\n            \"\"\"\n                |class TomlDecoder(\n                |    val elementsCount: Int = 100,\n                |    var elementsCount2: Int = 100\n                |)\n                |\n                |fun TomlDecoder(elementsCount: Int = 100) {}\n            \"\"\".trimMargin(),\n            rulesConfigList = rulesConfigIgnoreValueParameter\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.MAGIC_NUMBER)\n    fun `check ignore constant declaration`() {\n        lintMethod(\n            \"\"\"\n                |const val topLevel = 31\n            \"\"\".trimMargin(),\n            rulesConfigList = rulesConfigIgnoreConstantDeclaration\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.MAGIC_NUMBER)\n    fun `check ignore companion object property declaration`() {\n        lintMethod(\n            \"\"\"\n                |class A {\n                |   companion object {\n                |       val b = 3\n                |       var b2 = 4\n                |   }\n                |}\n            \"\"\".trimMargin(),\n            rulesConfigList = rulesConfigIgnoreCompanionObjectPropertyDeclaration\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.MAGIC_NUMBER)\n    fun `check ignore enums`() {\n        lintMethod(\n            \"\"\"\n                |enum class A(b:Int) {\n                |   A(3),\n                |   B(4),\n                |   C(5),\n                |}\n            \"\"\".trimMargin(),\n            rulesConfigList = rulesConfigIgnoreEnums\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.MAGIC_NUMBER)\n    fun `check ignore ranges`() {\n        lintMethod(\n            \"\"\"\n                |val tagLengthRange = 3..15\n                |var tagLengthRange2 = 3..15\n            \"\"\".trimMargin(),\n            rulesConfigList = rulesConfigIgnoreRanges\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.MAGIC_NUMBER)\n    fun `check ignore extension functions`() {\n        lintMethod(\n            \"\"\"\n                |fun Int.foo() = 3\n            \"\"\".trimMargin(),\n            rulesConfigList = rulesConfigIgnoreExtensionFunctions\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.MAGIC_NUMBER)\n    fun `check ignore pairs created using 'to'`() {\n        lintMethod(\n            \"\"\"\n                |val fg = abc to 3\n                |var fg2 = abc to 4\n            \"\"\".trimMargin(),\n            rulesConfigList = rulesConfigIgnorePairsCreatedUsingTo\n        )\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/test/kotlin/com/saveourtool/diktat/ruleset/chapter3/MultipleModifiersSequenceFixTest.kt",
    "content": "package com.saveourtool.diktat.ruleset.chapter3\n\nimport com.saveourtool.diktat.ruleset.rules.chapter3.MultipleModifiersSequence\nimport com.saveourtool.diktat.util.FixTestBase\n\nimport generated.WarningNames\nimport org.junit.jupiter.api.Tag\nimport org.junit.jupiter.api.Test\n\nclass MultipleModifiersSequenceFixTest : FixTestBase(\"test/paragraph3/multiple_modifiers\", ::MultipleModifiersSequence) {\n    @Test\n    @Tag(WarningNames.WRONG_MULTIPLE_MODIFIERS_ORDER)\n    fun `should fix modifiers order`() {\n        fixAndCompare(\"ModifierExpected.kt\", \"ModifierTest.kt\")\n    }\n\n    @Test\n    @Tag(WarningNames.WRONG_MULTIPLE_MODIFIERS_ORDER)\n    fun `should fix annotation order`() {\n        fixAndCompare(\"AnnotationExpected.kt\", \"AnnotationTest.kt\")\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/test/kotlin/com/saveourtool/diktat/ruleset/chapter3/MultipleModifiersSequenceWarnTest.kt",
    "content": "package com.saveourtool.diktat.ruleset.chapter3\n\nimport com.saveourtool.diktat.common.config.rules.DIKTAT_RULE_SET_ID\nimport com.saveourtool.diktat.ruleset.constants.Warnings.WRONG_MULTIPLE_MODIFIERS_ORDER\nimport com.saveourtool.diktat.ruleset.rules.chapter3.MultipleModifiersSequence\nimport com.saveourtool.diktat.util.LintTestBase\n\nimport com.saveourtool.diktat.api.DiktatError\nimport generated.WarningNames\nimport org.junit.jupiter.api.Tag\nimport org.junit.jupiter.api.Test\n\nclass MultipleModifiersSequenceWarnTest : LintTestBase(::MultipleModifiersSequence) {\n    private val ruleId = \"$DIKTAT_RULE_SET_ID:${MultipleModifiersSequence.NAME_ID}\"\n\n    @Test\n    @Tag(WarningNames.WRONG_MULTIPLE_MODIFIERS_ORDER)\n    fun `check wrong order modifier in fun and variable with annotation`() {\n        lintMethod(\n            \"\"\"\n                    |@Annotation\n                    |final public fun foo() {\n                    |   lateinit open protected var a: List<ASTNode>\n                    |}\n            \"\"\".trimMargin(),\n            DiktatError(2, 1, ruleId, \"${WRONG_MULTIPLE_MODIFIERS_ORDER.warnText()} final should be on position 2, but is on position 1\", true),\n            DiktatError(2, 7, ruleId, \"${WRONG_MULTIPLE_MODIFIERS_ORDER.warnText()} public should be on position 1, but is on position 2\", true),\n            DiktatError(3, 4, ruleId, \"${WRONG_MULTIPLE_MODIFIERS_ORDER.warnText()} lateinit should be on position 3, but is on position 1\", true),\n            DiktatError(3, 18, ruleId, \"${WRONG_MULTIPLE_MODIFIERS_ORDER.warnText()} protected should be on position 1, but is on position 3\", true)\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.WRONG_MULTIPLE_MODIFIERS_ORDER)\n    fun `check correct order modifier in fun and variable and without`() {\n        lintMethod(\n            \"\"\"\n                    |public final fun foo() {\n                    |   protected open lateinit var a: List<ASTNode>\n                    |}\n                    |\n                    |fun goo() {\n                    |\n                    |}\n            \"\"\".trimMargin()\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.WRONG_MULTIPLE_MODIFIERS_ORDER)\n    fun `check wrong order another modifier in fun`() {\n        lintMethod(\n            \"\"\"\n                    |inline tailrec public fun qwe(vararg text: String) {}\n                    |\n                    |inline suspend fun f(crossinline body: () -> Unit) {}\n                    |\n                    |inline  fun < reified T> membersOf() = T::class.members\n            \"\"\".trimMargin(),\n            DiktatError(1, 1, ruleId, \"${WRONG_MULTIPLE_MODIFIERS_ORDER.warnText()} inline should be on position 3, but is on position 1\", true),\n            DiktatError(1, 16, ruleId, \"${WRONG_MULTIPLE_MODIFIERS_ORDER.warnText()} public should be on position 1, but is on position 3\", true),\n            DiktatError(3, 1, ruleId, \"${WRONG_MULTIPLE_MODIFIERS_ORDER.warnText()} inline should be on position 2, but is on position 1\", true),\n            DiktatError(3, 8, ruleId, \"${WRONG_MULTIPLE_MODIFIERS_ORDER.warnText()} suspend should be on position 1, but is on position 2\", true)\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.WRONG_MULTIPLE_MODIFIERS_ORDER)\n    fun `check wrong order modifier in class`() {\n        lintMethod(\n            \"\"\"\n                    |enum public class Q {}\n                    |\n                    |data protected  class Counter(val dayIndex: Int) {\n                    |   operator suspend fun plus(increment: Int): Counter {\n                    |      return Counter(dayIndex + increment)\n                    |      }\n                    |}\n            \"\"\".trimMargin(),\n            DiktatError(1, 1, ruleId, \"${WRONG_MULTIPLE_MODIFIERS_ORDER.warnText()} enum should be on position 2, but is on position 1\", true),\n            DiktatError(1, 6, ruleId, \"${WRONG_MULTIPLE_MODIFIERS_ORDER.warnText()} public should be on position 1, but is on position 2\", true),\n            DiktatError(3, 1, ruleId, \"${WRONG_MULTIPLE_MODIFIERS_ORDER.warnText()} data should be on position 2, but is on position 1\", true),\n            DiktatError(3, 6, ruleId, \"${WRONG_MULTIPLE_MODIFIERS_ORDER.warnText()} protected should be on position 1, but is on position 2\", true),\n            DiktatError(4, 4, ruleId, \"${WRONG_MULTIPLE_MODIFIERS_ORDER.warnText()} operator should be on position 2, but is on position 1\", true),\n            DiktatError(4, 13, ruleId, \"${WRONG_MULTIPLE_MODIFIERS_ORDER.warnText()} suspend should be on position 1, but is on position 2\", true)\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.WRONG_MULTIPLE_MODIFIERS_ORDER)\n    fun `check wrong annotation order`() {\n        lintMethod(\n            \"\"\"\n                    |public @Annotation final fun foo() {\n                    |}\n            \"\"\".trimMargin(),\n            DiktatError(1, 8, ruleId, \"${WRONG_MULTIPLE_MODIFIERS_ORDER.warnText()} @Annotation annotation should be before all modifiers\", true)\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.WRONG_MULTIPLE_MODIFIERS_ORDER)\n    fun `check correct order modifier for value`() {\n        lintMethod(\n            \"\"\"\n                    |public value class Foo() {\n                    |}\n            \"\"\".trimMargin(),\n        )\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/test/kotlin/com/saveourtool/diktat/ruleset/chapter3/NullableTypeRuleFixTest.kt",
    "content": "package com.saveourtool.diktat.ruleset.chapter3\n\nimport com.saveourtool.diktat.ruleset.rules.chapter3.NullableTypeRule\nimport com.saveourtool.diktat.util.FixTestBase\n\nimport generated.WarningNames\nimport org.junit.jupiter.api.Tag\nimport org.junit.jupiter.api.Test\n\nclass NullableTypeRuleFixTest : FixTestBase(\"test/paragraph3/nullable\", ::NullableTypeRule) {\n    @Test\n    @Tag(WarningNames.NULLABLE_PROPERTY_TYPE)\n    fun `should fix primitive types`() {\n        fixAndCompare(\"NullPrimitiveExpected.kt\", \"NullPrimitiveTest.kt\")\n    }\n\n    @Test\n    @Tag(WarningNames.NULLABLE_PROPERTY_TYPE)\n    fun `should fix collections`() {\n        fixAndCompare(\"CollectionExpected.kt\", \"CollectionTest.kt\")\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/test/kotlin/com/saveourtool/diktat/ruleset/chapter3/NullableTypeRuleWarnTest.kt",
    "content": "package com.saveourtool.diktat.ruleset.chapter3\n\nimport com.saveourtool.diktat.common.config.rules.DIKTAT_RULE_SET_ID\nimport com.saveourtool.diktat.ruleset.constants.Warnings.NULLABLE_PROPERTY_TYPE\nimport com.saveourtool.diktat.ruleset.rules.chapter3.NullableTypeRule\nimport com.saveourtool.diktat.util.LintTestBase\n\nimport com.saveourtool.diktat.api.DiktatError\nimport generated.WarningNames\nimport org.junit.jupiter.api.Tag\nimport org.junit.jupiter.api.Test\n\nclass NullableTypeRuleWarnTest : LintTestBase(::NullableTypeRule) {\n    private val ruleId = \"$DIKTAT_RULE_SET_ID:${NullableTypeRule.NAME_ID}\"\n\n    @Test\n    @Tag(WarningNames.NULLABLE_PROPERTY_TYPE)\n    fun `check simple property`() {\n        lintMethod(\n            \"\"\"\n                    |val a: List<Int>? = null\n                    |val a: Int? = null\n                    |val b: Double? = null\n                    |val c: String? = null\n                    |val a: MutableList<Int>? = null\n            \"\"\".trimMargin(),\n            DiktatError(1, 21, ruleId, \"${NULLABLE_PROPERTY_TYPE.warnText()} initialize explicitly\", true),\n            DiktatError(2, 15, ruleId, \"${NULLABLE_PROPERTY_TYPE.warnText()} initialize explicitly\", true),\n            DiktatError(3, 18, ruleId, \"${NULLABLE_PROPERTY_TYPE.warnText()} initialize explicitly\", true),\n            DiktatError(4, 18, ruleId, \"${NULLABLE_PROPERTY_TYPE.warnText()} initialize explicitly\", true),\n            DiktatError(5, 28, ruleId, \"${NULLABLE_PROPERTY_TYPE.warnText()} initialize explicitly\", true)\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.NULLABLE_PROPERTY_TYPE)\n    fun `check property in object`() {\n        lintMethod(\n            \"\"\"\n                    |class A {\n                    |   companion object {\n                    |       val a: Int? = null\n                    |       val b: Int? = 0\n                    |       val c: Boolean? = true\n                    |   }\n                    |}\n            \"\"\".trimMargin(),\n            DiktatError(3, 22, ruleId, \"${NULLABLE_PROPERTY_TYPE.warnText()} initialize explicitly\", true),\n            DiktatError(4, 15, ruleId, \"${NULLABLE_PROPERTY_TYPE.warnText()} don't use nullable type\", false),\n            DiktatError(5, 15, ruleId, \"${NULLABLE_PROPERTY_TYPE.warnText()} don't use nullable type\", false)\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.NULLABLE_PROPERTY_TYPE)\n    fun `check nullable type with initialize`() {\n        lintMethod(\n            \"\"\"\n                    |class A {\n                    |   companion object {\n                    |       val a: Int? = 0\n                    |       val b: Int? = null\n                    |       val c: Boolean? = false\n                    |   }\n                    |}\n            \"\"\".trimMargin(),\n            DiktatError(3, 15, ruleId, \"${NULLABLE_PROPERTY_TYPE.warnText()} don't use nullable type\", false),\n            DiktatError(4, 22, ruleId, \"${NULLABLE_PROPERTY_TYPE.warnText()} initialize explicitly\", true),\n            DiktatError(5, 15, ruleId, \"${NULLABLE_PROPERTY_TYPE.warnText()} don't use nullable type\", false)\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.NULLABLE_PROPERTY_TYPE)\n    fun `d nullable type with initialize`() {\n        lintMethod(\n            \"\"\"\n                    |class A {\n                    |   val rulesConfigList: List<RulesConfig>? = RulesConfigReader(javaClass.classLoader).readResource(\"src/test/resources/test-rules-config.yml\")\n                    |   val q: Int? = foo()\n                    |   val e: A.Q? = null\n                    |}\n            \"\"\".trimMargin(),\n            DiktatError(4, 18, ruleId, \"${NULLABLE_PROPERTY_TYPE.warnText()} initialize explicitly\", false)\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.TYPE_ALIAS)\n    fun `should trigger on collection factory`() {\n        lintMethod(\n            \"\"\"\n                    | val q: List<Int>? = emptyList<Int>()\n                    | val w: List<Map<Int, Int>> = emptyList<Map<Int, Int>>()\n                    | val c: Set<Int>? = setOf()\n                    | val d: List<Int?> = emptyList()\n            \"\"\".trimMargin(),\n            DiktatError(1, 9, ruleId, \"${NULLABLE_PROPERTY_TYPE.warnText()} don't use nullable type\", false),\n            DiktatError(3, 9, ruleId, \"${NULLABLE_PROPERTY_TYPE.warnText()} don't use nullable type\", false)\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.TYPE_ALIAS)\n    fun `shouldn't trigger`() {\n        lintMethod(\n            \"\"\"\n                    | val superClassName: String? = node\n                    |   .getFirstChildWithType(ElementType.SUPER_TYPE_LIST)\n                    |   ?.findLeafWithSpecificType(TYPE_REFERENCE)\n                    |   ?.text\n                    |\n                    | private val rulesConfigList: List<RulesConfig>? = rulesConfigList ?: RulesConfigReader(javaClass.classLoader).readResource(\"diktat-analysis.yml\")\n            \"\"\".trimMargin())\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/test/kotlin/com/saveourtool/diktat/ruleset/chapter3/PreviewAnnotationFixTest.kt",
    "content": "package com.saveourtool.diktat.ruleset.chapter3\n\nimport com.saveourtool.diktat.ruleset.rules.chapter3.PreviewAnnotationRule\nimport com.saveourtool.diktat.util.FixTestBase\n\nimport generated.WarningNames\nimport org.junit.jupiter.api.Tag\nimport org.junit.jupiter.api.Test\n\nclass PreviewAnnotationFixTest : FixTestBase(\"test/paragraph3/preview_annotation\", ::PreviewAnnotationRule) {\n    @Test\n    @Tag(WarningNames.PREVIEW_ANNOTATION)\n    fun `should add private modifier`() {\n        fixAndCompare(\"PreviewAnnotationPrivateModifierExpected.kt\", \"PreviewAnnotationPrivateModifierTest.kt\")\n    }\n\n    @Test\n    @Tag(WarningNames.PREVIEW_ANNOTATION)\n    fun `should add Preview suffix`() {\n        fixAndCompare(\"PreviewAnnotationMethodNameExpected.kt\", \"PreviewAnnotationMethodNameTest.kt\")\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/test/kotlin/com/saveourtool/diktat/ruleset/chapter3/PreviewAnnotationWarnTest.kt",
    "content": "package com.saveourtool.diktat.ruleset.chapter3\n\nimport com.saveourtool.diktat.api.DiktatError\nimport com.saveourtool.diktat.common.config.rules.DIKTAT_RULE_SET_ID\nimport com.saveourtool.diktat.ruleset.constants.Warnings\nimport com.saveourtool.diktat.ruleset.rules.chapter3.PreviewAnnotationRule\nimport com.saveourtool.diktat.util.LintTestBase\nimport generated.WarningNames\nimport org.junit.jupiter.api.Tag\nimport org.junit.jupiter.api.Test\n\n\nclass PreviewAnnotationWarnTest : LintTestBase(::PreviewAnnotationRule) {\n    private val ruleId = \"$DIKTAT_RULE_SET_ID:${PreviewAnnotationRule.NAME_ID}\"\n\n    @Test\n    @Tag(WarningNames.PREVIEW_ANNOTATION)\n    fun `no warn`() {\n        lintMethod(\n            \"\"\"\n            |@Preview\n            |@Composable\n            |private fun BannerPreview() {}\n            \"\"\".trimMargin()\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.PREVIEW_ANNOTATION)\n    fun `method is not private`() {\n        lintMethod(\n            \"\"\"\n            |@Preview\n            |@Composable\n            |fun BannerPreview() {}\n            \"\"\".trimMargin(),\n            DiktatError(1, 1, ruleId, \"${Warnings.PREVIEW_ANNOTATION.warnText()} BannerPreview method should be private\", true),\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.PREVIEW_ANNOTATION)\n    fun `method has no preview suffix`() {\n        lintMethod(\n            \"\"\"\n            |@Preview\n            |@Composable\n            |private fun Banner() {}\n            \"\"\".trimMargin(),\n            DiktatError(1, 1, ruleId, \"${Warnings.PREVIEW_ANNOTATION.warnText()} Banner method should has `Preview` suffix\", true),\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.PREVIEW_ANNOTATION)\n    fun `method has no preview suffix and is not private`() {\n        lintMethod(\n            \"\"\"\n            |@Preview\n            |@Composable\n            |fun Banner() {}\n            \"\"\".trimMargin(),\n            DiktatError(1, 1, ruleId, \"${Warnings.PREVIEW_ANNOTATION.warnText()} Banner method should be private\", true),\n            DiktatError(1, 1, ruleId, \"${Warnings.PREVIEW_ANNOTATION.warnText()} Banner method should has `Preview` suffix\", true),\n        )\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/test/kotlin/com/saveourtool/diktat/ruleset/chapter3/RangeConventionalRuleFixTest.kt",
    "content": "package com.saveourtool.diktat.ruleset.chapter3\n\nimport com.saveourtool.diktat.ruleset.rules.chapter3.RangeConventionalRule\nimport com.saveourtool.diktat.util.FixTestBase\nimport org.junit.jupiter.api.Test\n\nclass RangeConventionalRuleFixTest : FixTestBase(\"test/paragraph3/range\", ::RangeConventionalRule) {\n    @Test\n    fun `should fix with until`() {\n        fixAndCompare(\"RangeToUntilExpected.kt\", \"RangeToUntilTest.kt\")\n    }\n\n    @Test\n    fun `should fix with rangeTo`() {\n        fixAndCompare(\"RangeToExpected.kt\", \"RangeToTest.kt\")\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/test/kotlin/com/saveourtool/diktat/ruleset/chapter3/RangeConventionalRuleWarnTest.kt",
    "content": "package com.saveourtool.diktat.ruleset.chapter3\n\nimport com.saveourtool.diktat.common.config.rules.DIKTAT_RULE_SET_ID\nimport com.saveourtool.diktat.common.config.rules.RulesConfig\nimport com.saveourtool.diktat.ruleset.constants.Warnings\nimport com.saveourtool.diktat.ruleset.rules.chapter3.RangeConventionalRule\nimport com.saveourtool.diktat.util.LintTestBase\n\nimport com.saveourtool.diktat.api.DiktatError\nimport org.junit.jupiter.api.Test\n\nclass RangeConventionalRuleWarnTest : LintTestBase(::RangeConventionalRule) {\n    private val ruleId = \"$DIKTAT_RULE_SET_ID:${RangeConventionalRule.NAME_ID}\"\n    private val rulesConfigRangeRule: List<RulesConfig> = listOf(\n        RulesConfig(\n            Warnings.CONVENTIONAL_RANGE.name, true,\n            mapOf(\"isRangeToIgnore\" to \"true\"))\n    )\n\n    @Test\n    fun `check simple examples with until`() {\n        lintMethod(\n            \"\"\"\n                    |fun foo() {\n                    |    for (i in 1..(4 - 1)) print(i)\n                    |    for (i in 1..(b - 1)) print(i)\n                    |    for (i in ((1 .. ((4 - 1))))) print(i)\n                    |    for (i in 4 downTo 1) print(i)\n                    |    for (i in 1..4) print(i)\n                    |    for (i in 1..4 step 2) print(i)\n                    |    for (i in 4 downTo 1 step 3) print(i)\n                    |    if (6 in (1..10) && true) {}\n                    |    for (i in 1..(4 - 1) step 3) print(i)\n                    |}\n            \"\"\".trimMargin(),\n            DiktatError(2, 15, ruleId, \"${Warnings.CONVENTIONAL_RANGE.warnText()} replace `..` with `until`: 1..(4 - 1)\", true),\n            DiktatError(3, 15, ruleId, \"${Warnings.CONVENTIONAL_RANGE.warnText()} replace `..` with `until`: 1..(b - 1)\", true),\n            DiktatError(4, 17, ruleId, \"${Warnings.CONVENTIONAL_RANGE.warnText()} replace `..` with `until`: 1 .. ((4 - 1))\", true),\n            DiktatError(10, 15, ruleId, \"${Warnings.CONVENTIONAL_RANGE.warnText()} replace `..` with `until`: 1..(4 - 1)\", true)\n        )\n    }\n\n    @Test\n    fun `check simple examples with rangeTo`() {\n        lintMethod(\n            \"\"\"\n                    |fun foo() {\n                    |    val num = 1\n                    |    val w = num.rangeTo(num, num)\n                    |    val q = 1..5\n                    |    val w = num.rangeTo(num)\n                    |}\n            \"\"\".trimMargin(),\n            DiktatError(5, 13, ruleId, \"${Warnings.CONVENTIONAL_RANGE.warnText()} replace `rangeTo` with `..`: num.rangeTo(num)\", true)\n        )\n    }\n\n    @Test\n    fun `check simple examples with rangeTo with config`() {\n        lintMethod(\n            \"\"\"\n                    |fun foo() {\n                    |    val w = num.rangeTo(num, num)\n                    |    val w = num.rangeTo(num)\n                    |}\n            \"\"\".trimMargin(),\n            rulesConfigList = rulesConfigRangeRule\n        )\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/test/kotlin/com/saveourtool/diktat/ruleset/chapter3/SingleLineStatementsRuleFixTest.kt",
    "content": "package com.saveourtool.diktat.ruleset.chapter3\n\nimport com.saveourtool.diktat.ruleset.rules.chapter3.SingleLineStatementsRule\nimport com.saveourtool.diktat.util.FixTestBase\n\nimport generated.WarningNames\nimport org.junit.jupiter.api.Tag\nimport org.junit.jupiter.api.Test\n\nclass SingleLineStatementsRuleFixTest : FixTestBase(\"test/paragraph3/statement\", ::SingleLineStatementsRule) {\n    @Test\n    @Tag(WarningNames.MORE_THAN_ONE_STATEMENT_PER_LINE)\n    fun `should make one statement per line`() {\n        fixAndCompare(\"StatementExpected.kt\", \"StatementTest.kt\")\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/test/kotlin/com/saveourtool/diktat/ruleset/chapter3/SingleLineStatementsRuleWarnTest.kt",
    "content": "package com.saveourtool.diktat.ruleset.chapter3\n\nimport com.saveourtool.diktat.common.config.rules.DIKTAT_RULE_SET_ID\nimport com.saveourtool.diktat.ruleset.constants.Warnings.MORE_THAN_ONE_STATEMENT_PER_LINE\nimport com.saveourtool.diktat.ruleset.rules.chapter3.SingleLineStatementsRule\nimport com.saveourtool.diktat.util.LintTestBase\n\nimport com.saveourtool.diktat.api.DiktatError\nimport generated.WarningNames\nimport org.junit.jupiter.api.Tag\nimport org.junit.jupiter.api.Test\n\nclass SingleLineStatementsRuleWarnTest : LintTestBase(::SingleLineStatementsRule) {\n    private val ruleId = \"$DIKTAT_RULE_SET_ID:${SingleLineStatementsRule.NAME_ID}\"\n\n    @Test\n    @Tag(WarningNames.MORE_THAN_ONE_STATEMENT_PER_LINE)\n    fun `check two statement per line`() {\n        lintMethod(\n            \"\"\"\n                    |import com.pinterest.ktlint.core.KtLint; import com.pinterest.ktlint.core.LintError\n                    |\n                    |fun foo() {\n                    |    if (x < -5) {\n                    |       goo(); hoo()\n                    |    }\n                    |    else {\n                    |    }\n                    |\n                    |    when(x) {\n                    |       1 -> println(1)\n                    |       else -> println(\"3;5\")\n                    |    }\n                    |    val a = 5; val b = 10\n                    |    println(1); println(1)\n                    |}\n            \"\"\".trimMargin(),\n            DiktatError(1, 40, ruleId, \"${MORE_THAN_ONE_STATEMENT_PER_LINE.warnText()} import com.pinterest.ktlint.core.KtLint; import com.pinterest.ktlint.core.LintError\", true),\n            DiktatError(5, 13, ruleId, \"${MORE_THAN_ONE_STATEMENT_PER_LINE.warnText()} goo(); hoo()\", true),\n            DiktatError(14, 14, ruleId, \"${MORE_THAN_ONE_STATEMENT_PER_LINE.warnText()} val a = 5; val b = 10\", true),\n            DiktatError(15, 15, ruleId, \"${MORE_THAN_ONE_STATEMENT_PER_LINE.warnText()} println(1); println(1)\", true)\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.MORE_THAN_ONE_STATEMENT_PER_LINE)\n    fun `check two statement in one line without space`() {\n        lintMethod(\n            \"\"\"\n                    |fun foo() {\n                    |    val a = 5;val b = 10\n                    |    println(1);println(1)\n                    |}\n            \"\"\".trimMargin(),\n            DiktatError(2, 14, ruleId, \"${MORE_THAN_ONE_STATEMENT_PER_LINE.warnText()} val a = 5;val b = 10\", true),\n            DiktatError(3, 15, ruleId, \"${MORE_THAN_ONE_STATEMENT_PER_LINE.warnText()} println(1);println(1)\", true)\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.MORE_THAN_ONE_STATEMENT_PER_LINE)\n    fun `check if expression with semicolon and else block in one line`() {\n        lintMethod(\n            \"\"\"\n                    |fun foo() {\n                    |   if (x > 0){\n                    |       goo()\n                    |   }; else { print(123) }\n                    |}\n            \"\"\".trimMargin(),\n            DiktatError(4, 5, ruleId, \"${MORE_THAN_ONE_STATEMENT_PER_LINE.warnText()} }; else { print(123) }\", true)\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.MORE_THAN_ONE_STATEMENT_PER_LINE)\n    fun `check correct test without more than one statement`() {\n        lintMethod(\n            \"\"\"\n                    |import com.pinterest.ktlint.core.KtLint\n                    |\n                    |fun foo() {\n                    |    if (x < -5) {\n                    |       goo();\n                    |    }\n                    |    else {\n                    |    }\n                    |\n                    |    when(x) {\n                    |       1 -> println(1)\n                    |       else -> println(\"3;5\")\n                    |    }\n                    |    val a = 5\n                    |    println(1)\n                    |}\n            \"\"\".trimMargin()\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.MORE_THAN_ONE_STATEMENT_PER_LINE)\n    fun `check semicolon with enum class expression`() {\n        lintMethod(\n            \"\"\"\n                    |enum class ProtocolState {\n                    |   WAITING {\n                    |       override fun signal() = TALKING\n                    |   },\n                    |   TALKING {\n                    |       override fun signal() = WAITING\n                    |   }; abstract fun signal(): ProtocolState\n                    |}\n            \"\"\".trimMargin(),\n            DiktatError(7, 5, ruleId, \"${MORE_THAN_ONE_STATEMENT_PER_LINE.warnText()} }; abstract fun signal(): ProtocolState\", true)\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.MORE_THAN_ONE_STATEMENT_PER_LINE)\n    fun `check if expression with two wrong semincolon`() {\n        lintMethod(\n            \"\"\"\n                    |fun foo() {\n                    |   if(x > 0) {\n                    |       if ( y> 0){\n                    |           ji()\n                    |       }; gt()\n                    |   }; gr()\n                    |}\n            \"\"\".trimMargin(),\n            DiktatError(5, 9, ruleId, \"${MORE_THAN_ONE_STATEMENT_PER_LINE.warnText()} }; gt()\", true),\n            DiktatError(6, 5, ruleId, \"${MORE_THAN_ONE_STATEMENT_PER_LINE.warnText()} }; gr()\", true)\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.MORE_THAN_ONE_STATEMENT_PER_LINE)\n    fun `check semicolon in the beginning of the line`() {\n        lintMethod(\n            \"\"\"\n                    |fun foo() {\n                    |   ; grr()\n                    |}\n            \"\"\".trimMargin(),\n            DiktatError(2, 4, ruleId, \"${MORE_THAN_ONE_STATEMENT_PER_LINE.warnText()} ; grr()\", true)\n        )\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/test/kotlin/com/saveourtool/diktat/ruleset/chapter3/SortRuleFixTest.kt",
    "content": "package com.saveourtool.diktat.ruleset.chapter3\n\nimport com.saveourtool.diktat.common.config.rules.RulesConfig\nimport com.saveourtool.diktat.ruleset.constants.Warnings\nimport com.saveourtool.diktat.ruleset.rules.chapter3.SortRule\nimport com.saveourtool.diktat.util.FixTestBase\n\nimport generated.WarningNames\nimport org.junit.jupiter.api.Tag\nimport org.junit.jupiter.api.Test\n\nclass SortRuleFixTest : FixTestBase(\"test/paragraph3/sort_error\", ::SortRule) {\n    private val rulesConfigSortEnum: List<RulesConfig> = listOf(\n        RulesConfig(Warnings.WRONG_DECLARATIONS_ORDER.name, true,\n            mapOf(\"sortEnum\" to \"true\"))\n    )\n    private val rulesConfigSortProperty: List<RulesConfig> = listOf(\n        RulesConfig(Warnings.WRONG_DECLARATIONS_ORDER.name, true,\n            mapOf(\"sortProperty\" to \"true\"))\n    )\n\n    @Test\n    @Tag(WarningNames.WRONG_DECLARATIONS_ORDER)\n    fun `should fix enum order`() {\n        fixAndCompare(\"EnumSortExpected.kt\", \"EnumSortTest.kt\", rulesConfigSortEnum)\n    }\n\n    @Test\n    @Tag(WarningNames.WRONG_DECLARATIONS_ORDER)\n    fun `should fix constants order`() {\n        fixAndCompare(\"ConstantsExpected.kt\", \"ConstantsTest.kt\", rulesConfigSortProperty)\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/test/kotlin/com/saveourtool/diktat/ruleset/chapter3/SortRuleWarnTest.kt",
    "content": "package com.saveourtool.diktat.ruleset.chapter3\n\nimport com.saveourtool.diktat.common.config.rules.DIKTAT_RULE_SET_ID\nimport com.saveourtool.diktat.common.config.rules.RulesConfig\nimport com.saveourtool.diktat.ruleset.constants.Warnings.WRONG_DECLARATIONS_ORDER\nimport com.saveourtool.diktat.ruleset.rules.chapter3.SortRule\nimport com.saveourtool.diktat.util.LintTestBase\n\nimport com.saveourtool.diktat.api.DiktatError\nimport generated.WarningNames\nimport org.junit.jupiter.api.Tag\nimport org.junit.jupiter.api.Test\n\nclass SortRuleWarnTest : LintTestBase(::SortRule) {\n    private val ruleId = \"$DIKTAT_RULE_SET_ID:${SortRule.NAME_ID}\"\n    private val rulesConfigNotSortEnum: List<RulesConfig> = listOf(\n        RulesConfig(WRONG_DECLARATIONS_ORDER.name, true,\n            mapOf(\"sortEnum\" to \"false\"))\n    )\n    private val rulesConfigNotSortProperty: List<RulesConfig> = listOf(\n        RulesConfig(WRONG_DECLARATIONS_ORDER.name, true,\n            mapOf(\"sortProperty\" to \"false\"))\n    )\n    private val rulesConfigNotSortBoth: List<RulesConfig> = listOf(\n        RulesConfig(WRONG_DECLARATIONS_ORDER.name, true,\n            mapOf(\"sortProperty\" to \"false\", \"sortEnum\" to \"false\"))\n    )\n\n    @Test\n    @Tag(WarningNames.WRONG_DECLARATIONS_ORDER)\n    fun `check simple correct enum`() {\n        lintMethod(\n            \"\"\"\n                    |enum class Alph {\n                    |   A,\n                    |   B,\n                    |   C,\n                    |   D,\n                    |   ;\n                    |}\n            \"\"\".trimMargin()\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.WRONG_DECLARATIONS_ORDER)\n    fun `check simple wrong enum`() {\n        lintMethod(\n            \"\"\"\n                    |enum class Alph {\n                    |   D,\n                    |   C,\n                    |   A,\n                    |   B,\n                    |   ;\n                    |}\n            \"\"\".trimMargin(),\n            DiktatError(1, 17, ruleId, \"${WRONG_DECLARATIONS_ORDER.warnText()} enum entries order is incorrect\", true)\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.WRONG_DECLARATIONS_ORDER)\n    fun `check correct enum`() {\n        lintMethod(\n            \"\"\"\n                    |enum class ENUM {\n                    |   BLUE(0x0000FF),\n                    |   GREEN(0x00FF00),\n                    |   RED(0xFF0000),\n                    |   ;\n                    |}\n            \"\"\".trimMargin()\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.WRONG_DECLARATIONS_ORDER)\n    fun `check wrong enum without semicolon`() {\n        lintMethod(\n            \"\"\"\n                    |enum class ENUM {\n                    |   GREEN(0x00FF00),\n                    |   RED(0xFF0000),\n                    |   BLUE(0x0000FF),\n                    |}\n            \"\"\".trimMargin(),\n            DiktatError(1, 17, ruleId, \"${WRONG_DECLARATIONS_ORDER.warnText()} enum entries order is incorrect\", true)\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.WRONG_DECLARATIONS_ORDER)\n    fun `check wrong enum without semicolon and last comma`() {\n        lintMethod(\n            \"\"\"\n                    |enum class ENUM {\n                    |   GREEN(0x00FF00),\n                    |   RED(0xFF0000),\n                    |   BLUE(0x0000FF)\n                    |}\n            \"\"\".trimMargin(),\n            DiktatError(1, 17, ruleId, \"${WRONG_DECLARATIONS_ORDER.warnText()} enum entries order is incorrect\", true)\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.WRONG_DECLARATIONS_ORDER)\n    fun `check correct enum without semicolon and last comma`() {\n        lintMethod(\n            \"\"\"\n                    |enum class ENUM {\n                    |   BLUE(0x0000FF),\n                    |   GREEN(0x00FF00),\n                    |   RED(0xFF0000),\n                    |}\n            \"\"\".trimMargin()\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.WRONG_DECLARATIONS_ORDER)\n    fun `check wrong enum with fun`() {\n        lintMethod(\n            \"\"\"\n                    |enum class Warnings {\n                    |   WAITING {\n                    |      override fun signal() = TALKING\n                    |   },\n                    |   TALKING  {\n                    |      override fun signal() = TALKING\n                    |   },\n                    |   ;\n                    |   abstract fun signal(): ProtocolState\n                    |}\n            \"\"\".trimMargin(),\n            DiktatError(1, 21, ruleId, \"${WRONG_DECLARATIONS_ORDER.warnText()} enum entries order is incorrect\", true)\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.WRONG_DECLARATIONS_ORDER)\n    fun `check wrong enum with fun but with config`() {\n        lintMethod(\n            \"\"\"\n                    |enum class Warnings {\n                    |   WAITING {\n                    |      override fun signal() = TALKING\n                    |   },\n                    |   TALKING  {\n                    |      override fun signal() = TALKING\n                    |   },\n                    |   ;\n                    |   abstract fun signal(): ProtocolState\n                    |}\n            \"\"\".trimMargin(), rulesConfigList = rulesConfigNotSortEnum\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.WRONG_DECLARATIONS_ORDER)\n    fun `check wrong properties between non conts`() {\n        lintMethod(\n            \"\"\"\n                    |class A {\n                    |   companion object {\n                    |       private val log = \"Log\"\n                    |       private const val B = 4\n                    |       private const val A = 5\n                    |       private val SIMPLE_VALUE = listOf(IDENTIFIER, WHITE_SPACE, COMMA, SEMICOLON)\n                    |       private const val A = 5\n                    |   }\n                    |}\n            \"\"\".trimMargin(),\n            DiktatError(4, 8, ruleId, \"${WRONG_DECLARATIONS_ORDER.warnText()} constant properties inside companion object order is incorrect\", true)\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.WRONG_DECLARATIONS_ORDER)\n    fun `check wrong properties between non const more than one group`() {\n        lintMethod(\n            \"\"\"\n                    |class A {\n                    |   companion object {\n                    |       private val log = \"Log\"\n                    |       private const val B = 4\n                    |       private const val A = 5\n                    |       private val SIMPLE_VALUE = listOf(IDENTIFIER, WHITE_SPACE, COMMA, SEMICOLON)\n                    |       private const val Daa = 5\n                    |       private const val Da = 5\n                    |       private const val Db = 5\n                    |   }\n                    |}\n            \"\"\".trimMargin(),\n            DiktatError(4, 8, ruleId, \"${WRONG_DECLARATIONS_ORDER.warnText()} constant properties inside companion object order is incorrect\", true),\n            DiktatError(7, 8, ruleId, \"${WRONG_DECLARATIONS_ORDER.warnText()} constant properties inside companion object order is incorrect\", true)\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.WRONG_DECLARATIONS_ORDER)\n    fun `check wrong properties between non const more than one group only one`() {\n        lintMethod(\n            \"\"\"\n                    |class A {\n                    |   companion object {\n                    |       private val log = \"Log\"\n                    |       private const val A = 4\n                    |       private const val D = 5\n                    |       private val SIMPLE_VALUE = listOf(IDENTIFIER, WHITE_SPACE, COMMA, SEMICOLON)\n                    |       private const val Daa = 5\n                    |       private const val Da = 5\n                    |       private const val Db = 5\n                    |   }\n                    |}\n            \"\"\".trimMargin(),\n            DiktatError(7, 8, ruleId, \"${WRONG_DECLARATIONS_ORDER.warnText()} constant properties inside companion object order is incorrect\", true)\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.WRONG_DECLARATIONS_ORDER)\n    fun `check wrong properties but with config`() {\n        lintMethod(\n            \"\"\"\n                    |class A {\n                    |   companion object {\n                    |       private val log = \"Log\"\n                    |       private const val A = 4\n                    |       private const val D = 5\n                    |       private val SIMPLE_VALUE = listOf(IDENTIFIER, WHITE_SPACE, COMMA, SEMICOLON)\n                    |       private const val Daa = 5\n                    |       private const val Da = 5\n                    |       private const val Db = 5\n                    |   }\n                    |}\n            \"\"\".trimMargin(), rulesConfigList = rulesConfigNotSortProperty\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.WRONG_DECLARATIONS_ORDER)\n    fun `check wrong properties but with both config`() {\n        lintMethod(\n            \"\"\"\n                    |class A {\n                    |   companion object {\n                    |       private val log = \"Log\"\n                    |       private const val A = 4\n                    |       private const val D = 5\n                    |       private val SIMPLE_VALUE = listOf(IDENTIFIER, WHITE_SPACE, COMMA, SEMICOLON)\n                    |       private const val Daa = 5\n                    |       private const val Da = 5\n                    |       private const val Db = 5\n                    |   }\n                    |}\n                    |enum class Warnings {\n                    |   WAITING {\n                    |      override fun signal() = TALKING\n                    |   },\n                    |   TALKING  {\n                    |      override fun signal() = TALKING\n                    |   },\n                    |   ;\n                    |   abstract fun signal(): ProtocolState\n                    |}\n            \"\"\".trimMargin(), rulesConfigList = rulesConfigNotSortBoth\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.WRONG_DECLARATIONS_ORDER)\n    fun `check correct simple properties`() {\n        lintMethod(\n            \"\"\"\n                    |class A {\n                    |   companion object {\n                    |       private const val A = 5\n                    |       private const val B = 4\n                    |   }\n                    |}\n            \"\"\".trimMargin()\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.WRONG_DECLARATIONS_ORDER)\n    fun `check correct simple properties between non const`() {\n        lintMethod(\n            \"\"\"\n                    |class A {\n                    |   companion object {\n                    |       private const val D = 4\n                    |       private val SIMPLE_VALUE = listOf(IDENTIFIER, WHITE_SPACE, COMMA, SEMICOLON)\n                    |       private const val B = 4\n                    |       private val SIMPLE_VALUE = listOf(IDENTIFIER, WHITE_SPACE, COMMA, SEMICOLON)\n                    |       private const val C = 4\n                    |       private val SIMPLE_VALUE = listOf(IDENTIFIER, WHITE_SPACE, COMMA, SEMICOLON)\n                    |   }\n                    |}\n            \"\"\".trimMargin()\n        )\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/test/kotlin/com/saveourtool/diktat/ruleset/chapter3/StringConcatenationRuleFixTest.kt",
    "content": "package com.saveourtool.diktat.ruleset.chapter3\n\nimport com.saveourtool.diktat.common.config.rules.RulesConfig\nimport com.saveourtool.diktat.ruleset.constants.Warnings\nimport com.saveourtool.diktat.ruleset.rules.chapter3.StringConcatenationRule\nimport com.saveourtool.diktat.util.FixTestBase\n\nimport generated.WarningNames\nimport org.junit.jupiter.api.Tag\nimport org.junit.jupiter.api.Test\n\nclass StringConcatenationRuleFixTest : FixTestBase(\n    \"test/paragraph3/string_concatenation\",\n    ::StringConcatenationRule,\n    listOf(\n        RulesConfig(Warnings.STRING_CONCATENATION.name, true, emptyMap())\n    )\n) {\n    @Test\n    @Tag(WarningNames.STRING_CONCATENATION)\n    fun `fixing string concatenation`() {\n        fixAndCompare(\"StringConcatenationExpected.kt\", \"StringConcatenationTest.kt\")\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/test/kotlin/com/saveourtool/diktat/ruleset/chapter3/StringConcatenationWarnTest.kt",
    "content": "package com.saveourtool.diktat.ruleset.chapter3\n\nimport com.saveourtool.diktat.common.config.rules.DIKTAT_RULE_SET_ID\nimport com.saveourtool.diktat.ruleset.constants.Warnings\nimport com.saveourtool.diktat.ruleset.rules.chapter3.StringConcatenationRule\nimport com.saveourtool.diktat.util.LintTestBase\n\nimport com.saveourtool.diktat.api.DiktatError\nimport generated.WarningNames\nimport org.junit.jupiter.api.Tag\nimport org.junit.jupiter.api.Test\n\nclass StringConcatenationWarnTest : LintTestBase(::StringConcatenationRule) {\n    private val ruleId = \"$DIKTAT_RULE_SET_ID:${StringConcatenationRule.NAME_ID}\"\n    private val canBeAutoCorrected = true\n\n    @Test\n    @Tag(WarningNames.STRING_CONCATENATION)\n    fun `string concatenation - only strings`() {\n        lintMethod(\n            \"\"\"\n                    | val a = \"my string\" + \"string\" + value + \"other value\"\n                    |\n            \"\"\".trimMargin(),\n            DiktatError(1, 10, ruleId, Warnings.STRING_CONCATENATION.warnText() +\n                    \" \\\"my string\\\" + \\\"string\\\" + value + \\\"other value\\\"\", canBeAutoCorrected)\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.STRING_CONCATENATION)\n    fun `string concatenation - simple string and integers`() {\n        lintMethod(\n            \"\"\"\n                    | val a = \"my string\" + 1 + 2 + 3\n                    |\n            \"\"\".trimMargin(),\n            DiktatError(1, 10, ruleId, Warnings.STRING_CONCATENATION.warnText() +\n                    \" \\\"my string\\\" + 1 + 2 + 3\", canBeAutoCorrected)\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.STRING_CONCATENATION)\n    // FixMe: need to check and think if this codeblock should trigger warning or not\n    fun `string concatenation - toString function in string templates`() {\n        lintMethod(\n            \"\"\"\n                    | val a = (1 + 2).toString() + \"my string\" + 3\n                    |\n            \"\"\".trimMargin(),\n            DiktatError(1, 10, ruleId, Warnings.STRING_CONCATENATION.warnText() +\n                    \" (1 + 2).toString() + \\\"my string\\\" + 3\", canBeAutoCorrected)\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.STRING_CONCATENATION)\n    fun `string concatenation - toString and variables`() {\n        lintMethod(\n            \"\"\"\n                    | val myObject = 12\n                    | val a = (1 + 2).toString() + \"my string\" + 3 + \"string\" + myObject + myObject\n                    |\n            \"\"\".trimMargin(),\n            DiktatError(2, 10, ruleId, Warnings.STRING_CONCATENATION.warnText() +\n                    \" (1 + 2).toString() + \\\"my string\\\" + 3 + \\\"string\\\" + myObject + myObject\", canBeAutoCorrected)\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.STRING_CONCATENATION)\n    fun `string concatenation - toString and variables with braces`() {\n        lintMethod(\n            \"\"\"\n                    | val myObject = 12\n                    | val a = (1 + 2).toString() + \"my string\" + (\"string\" + myObject) + myObject\n                    |\n            \"\"\".trimMargin(),\n            DiktatError(2, 10, ruleId, Warnings.STRING_CONCATENATION.warnText() +\n                    \" (1 + 2).toString() + \\\"my string\\\" + (\\\"string\\\" + myObject) + myObject\", canBeAutoCorrected)\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.STRING_CONCATENATION)\n    fun `string concatenation - function argument`() {\n        lintMethod(\n            \"\"\"\n                    | fun foo1(){\n                    |     foo(\"my string\" + \"other string\" + (1 + 2 + 3))\n                    | }\n            \"\"\".trimMargin(),\n            DiktatError(2, 10, ruleId, Warnings.STRING_CONCATENATION.warnText() +\n                    \" \\\"my string\\\" + \\\"other string\\\" + (1 + 2 + 3)\", canBeAutoCorrected)\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.STRING_CONCATENATION)\n    fun `string concatenation - string and braces`() {\n        lintMethod(\n            \"\"\"\n                    | val myObject = 12\n                    | val a = \"my string\" + \"other string\" + (1 + 2 + 3)\n                    |\n            \"\"\".trimMargin(),\n            DiktatError(2, 10, ruleId, Warnings.STRING_CONCATENATION.warnText() +\n                    \" \\\"my string\\\" + \\\"other string\\\" + (1 + 2 + 3)\", canBeAutoCorrected)\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.STRING_CONCATENATION)\n    fun `string concatenation - several braces`() {\n        lintMethod(\n            \"\"\"\n                    | val myObject = 12\n                    | val a = \"my string\" + (1 + 2 + 3) + (\"other string\" + 3) + (1 + 2 + 3)\n                    |\n            \"\"\".trimMargin(),\n            DiktatError(2, 10, ruleId, Warnings.STRING_CONCATENATION.warnText() +\n                    \" \\\"my string\\\" + (1 + 2 + 3) + (\\\"other string\\\" + 3) + (1 + 2 + 3)\", canBeAutoCorrected)\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.STRING_CONCATENATION)\n    fun `string concatenation - multiple braces`() {\n        lintMethod(\n            \"\"\"\n                    | val a = \"my string\" + (1 + 2 + 3) + (\"other string\" + 3) + (1 + (2 + 3)) + (\"third string\" + (\"str\" + 5))\n                    |\n            \"\"\".trimMargin(),\n            DiktatError(1, 10, ruleId, Warnings.STRING_CONCATENATION.warnText() +\n                    \" \\\"my string\\\" + (1 + 2 + 3) + (\\\"other string\\\" + 3) + (1 + (2 + 3)) +\" +\n                    \" (\\\"third string\\\" + (\\\"str\\\" + 5))\", canBeAutoCorrected)\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.STRING_CONCATENATION)\n    fun `string concatenation - other binary operators`() {\n        lintMethod(\n            \"\"\"\n                    | val a = \"my string\" + (\"third string\" + (\"str\" + 5 * 12 / 100))\n                    |\n            \"\"\".trimMargin(),\n            DiktatError(1, 10, ruleId, Warnings.STRING_CONCATENATION.warnText() +\n                    \" \\\"my string\\\" + (\\\"third string\\\" + (\\\"str\\\" + 5 * 12 / 100))\", canBeAutoCorrected)\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.STRING_CONCATENATION)\n    fun `string concatenation - three lines `() {\n        lintMethod(\n            \"\"\"\n                    | val a = \"my string\" +\n                    |  \"string\" + value +\n                    |  other + value\n                    |\n            \"\"\".trimMargin()\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.STRING_CONCATENATION)\n    fun `string concatenation - two lines `() {\n        lintMethod(\n            \"\"\"\n                    | val a = \"my string\" +\n                    |  \"string\" + value\n                    |\n            \"\"\".trimMargin()\n        )\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/test/kotlin/com/saveourtool/diktat/ruleset/chapter3/StringTemplateRuleFixTest.kt",
    "content": "package com.saveourtool.diktat.ruleset.chapter3\n\nimport com.saveourtool.diktat.ruleset.rules.chapter3.StringTemplateFormatRule\nimport com.saveourtool.diktat.util.FixTestBase\n\nimport generated.WarningNames\nimport org.junit.jupiter.api.Tag\nimport org.junit.jupiter.api.Test\n\nclass StringTemplateRuleFixTest : FixTestBase(\"test/paragraph3/string_template\", ::StringTemplateFormatRule) {\n    @Test\n    @Tag(WarningNames.STRING_TEMPLATE_CURLY_BRACES)\n    fun `should fix enum order`() {\n        fixAndCompare(\"StringTemplateExpected.kt\", \"StringTemplateTest.kt\")\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/test/kotlin/com/saveourtool/diktat/ruleset/chapter3/StringTemplateRuleWarnTest.kt",
    "content": "package com.saveourtool.diktat.ruleset.chapter3\n\nimport com.saveourtool.diktat.common.config.rules.DIKTAT_RULE_SET_ID\nimport com.saveourtool.diktat.ruleset.constants.Warnings\nimport com.saveourtool.diktat.ruleset.rules.chapter3.StringTemplateFormatRule\nimport com.saveourtool.diktat.util.LintTestBase\n\nimport com.saveourtool.diktat.api.DiktatError\nimport generated.WarningNames.STRING_TEMPLATE_CURLY_BRACES\nimport generated.WarningNames.STRING_TEMPLATE_QUOTES\nimport org.junit.jupiter.api.Tag\nimport org.junit.jupiter.api.Test\n\nclass StringTemplateRuleWarnTest : LintTestBase(::StringTemplateFormatRule) {\n    private val ruleId = \"$DIKTAT_RULE_SET_ID:${StringTemplateFormatRule.NAME_ID}\"\n\n    @Test\n    @Tag(STRING_TEMPLATE_CURLY_BRACES)\n    fun `long string template good example`() {\n        lintMethod(\n            \"\"\"\n                    |class Some {\n                    |   val template = \"${'$'}{::String} ${'$'}{asd.moo()}\"\n                    |   val some = \"${'$'}{foo as Foo}\"\n                    |}\n            \"\"\".trimMargin()\n        )\n    }\n\n    @Test\n    @Tag(STRING_TEMPLATE_CURLY_BRACES)\n    fun `long string template bad example`() {\n        lintMethod(\n            \"\"\"\n                    |class Some {\n                    |   val template = \"${'$'}{a} ${'$'}{asd.moo()}\"\n                    |   val some = \"${'$'}{1.0}\"\n                    |   val another = \"${'$'}{1}\"\n                    |   val singleLetterCase = \"${'$'}{ref}\"\n                    |   val digitsWithLetters = \"${'$'}{1.0}asd\"\n                    |}\n            \"\"\".trimMargin(),\n            DiktatError(2, 20, ruleId, \"${Warnings.STRING_TEMPLATE_CURLY_BRACES.warnText()} ${'$'}{a}\", true),\n            DiktatError(3, 16, ruleId, \"${Warnings.STRING_TEMPLATE_CURLY_BRACES.warnText()} ${'$'}{1.0}\", true),\n            DiktatError(4, 19, ruleId, \"${Warnings.STRING_TEMPLATE_CURLY_BRACES.warnText()} ${'$'}{1}\", true),\n            DiktatError(5, 28, ruleId, \"${Warnings.STRING_TEMPLATE_CURLY_BRACES.warnText()} ${'$'}{ref}\", true),\n            DiktatError(6, 29, ruleId, \"${Warnings.STRING_TEMPLATE_CURLY_BRACES.warnText()} ${'$'}{1.0}\", true)\n        )\n    }\n\n    @Test\n    @Tag(STRING_TEMPLATE_QUOTES)\n    fun `short string template bad example`() {\n        lintMethod(\n            \"\"\"\n                    |class Some {\n                    |   val template = \"${'$'}a\"\n                    |   val z = a\n                    |}\n            \"\"\".trimMargin(),\n            DiktatError(2, 20, ruleId, \"${Warnings.STRING_TEMPLATE_QUOTES.warnText()} ${'$'}a\", true)\n        )\n    }\n\n    @Test\n    @Tag(STRING_TEMPLATE_CURLY_BRACES)\n    fun `should trigger on dot after braces`() {\n        lintMethod(\n            \"\"\"\n                    |class Some {\n                    |   fun some() {\n                    |       val s = \"abs\"\n                    |       println(\"${'$'}{s}.length is ${'$'}{s.length}\")\n                    |   }\n                    |}\n            \"\"\".trimMargin(),\n            DiktatError(4, 17, ruleId, \"${Warnings.STRING_TEMPLATE_CURLY_BRACES.warnText()} ${'$'}{s}\", true)\n        )\n    }\n\n    @Test\n    @Tag(STRING_TEMPLATE_QUOTES)\n    fun `should not trigger`() {\n        lintMethod(\n            \"\"\"\n                    |class Some {\n                    |   fun some() {\n                    |       val price = \"\"${'\"'}\n                    |       ${'$'}9.99\n                    |       \"\"${'\"'}\n                    |       val some = \"${'$'}{index + 1}\"\n                    |   }\n                    |}\n            \"\"\".trimMargin()\n        )\n    }\n\n    @Test\n    @Tag(STRING_TEMPLATE_CURLY_BRACES)\n    fun `underscore after braces - braces should not be removed`() {\n        lintMethod(\n            \"\"\"\n                    |class Some {\n                    |   fun some() {\n                    |       val copyTestFile = File(\"${'$'}{testFile()} copy ${'$'}{testFile}_copy\")\n                    |   }\n                    |}\n            \"\"\".trimMargin()\n        )\n    }\n\n    @Test\n    @Tag(STRING_TEMPLATE_CURLY_BRACES)\n    fun `should not trigger on array access`() {\n        lintMethod(\n            \"\"\"\n                    |class Some {\n                    |   fun some() {\n                    |       val copyTestFile = \"${'$'}{arr[0]}\"\n                    |   }\n                    |}\n            \"\"\".trimMargin()\n        )\n    }\n\n    @Test\n    @Tag(STRING_TEMPLATE_QUOTES)\n    fun `should trigger on long string template`() {\n        lintMethod(\n            \"\"\"\n                    |class Some {\n                    |   fun some() {\n                    |       val x = \"asd\"\n                    |       val trippleQuotes = \"\"${'\"'}${'$'}x\"\"${'\"'}\n                    |   }\n                    |}\n            \"\"\".trimMargin(),\n            DiktatError(4, 31, ruleId, \"${Warnings.STRING_TEMPLATE_QUOTES.warnText()} ${'$'}x\", true)\n        )\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/test/kotlin/com/saveourtool/diktat/ruleset/chapter3/SuperClassListWarnTest.kt",
    "content": "package com.saveourtool.diktat.ruleset.chapter3\n\nimport com.saveourtool.diktat.common.config.rules.DIKTAT_RULE_SET_ID\nimport com.saveourtool.diktat.ruleset.constants.Warnings.WRONG_NEWLINES\nimport com.saveourtool.diktat.ruleset.rules.chapter3.files.NewlinesRule\nimport com.saveourtool.diktat.util.LintTestBase\n\nimport com.saveourtool.diktat.api.DiktatError\nimport com.saveourtool.diktat.ruleset.constants.Warnings\nimport generated.WarningNames\nimport org.junit.jupiter.api.Tag\nimport org.junit.jupiter.api.Test\n\nclass SuperClassListWarnTest : LintTestBase(::NewlinesRule) {\n    private val ruleId = \"$DIKTAT_RULE_SET_ID:${NewlinesRule.NAME_ID}\"\n\n    @Test\n    @Tag(WarningNames.WRONG_NEWLINES)\n    fun `superclass list on the same line`() {\n        lintMethod(\n            \"\"\"\n                    |package com.saveourtool.diktat\n                    |\n                    |class A<K : Any, P : Any, G : Any> : B<K>(), C<P>, D<G> {}\n            \"\"\".trimMargin(),\n            DiktatError(3, 38, ruleId, \"${Warnings.WRONG_NEWLINES.warnText()} supertype list entries should be placed on different lines in declaration of <A>\", true),\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.WRONG_NEWLINES)\n    fun `first superclass also on a new line`() {\n        lintMethod(\n            \"\"\"\n                    |package com.saveourtool.diktat\n                    |\n                    |class A<K : Any, P : Any, G : Any> : B<K>(),\n                    |C<P>,\n                    |D<G> {}\n            \"\"\".trimMargin(),\n            DiktatError(3, 38, ruleId, \"${Warnings.WRONG_NEWLINES.warnText()} supertype list entries should be placed on different lines in declaration of <A>\", true),\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.WRONG_NEWLINES)\n    fun `superclass list of 2 elements on the same line`() {\n        lintMethod(\n            \"\"\"\n                    |package com.saveourtool.diktat\n                    |\n                    |class A<K : Any, P : Any, G : Any> : B<K>(), C<P> {}\n            \"\"\".trimMargin(),\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.WRONG_NEWLINES)\n    fun `superclass list on separate lines`() {\n        lintMethod(\n            \"\"\"\n                    |package com.saveourtool.diktat\n                    |\n                    |class A<K : Any, P : Any, G : Any> :\n                    |B<K>(),\n                    |C<P>,\n                    |D<G> {}\n            \"\"\".trimMargin(),\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.WRONG_NEWLINES)\n    fun `superclass list different whitespaces`() {\n        lintMethod(\n            \"\"\"\n                    |package com.saveourtool.diktat\n                    |\n                    |class A<K : Any, P : Any, G : Any> :\n                    |B<K>(),\n                    |    C<P>, D<G> {}\n            \"\"\".trimMargin(),\n            DiktatError(4, 1, ruleId, \"${Warnings.WRONG_NEWLINES.warnText()} supertype list entries should be placed on different lines in declaration of <A>\", true),\n            )\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/test/kotlin/com/saveourtool/diktat/ruleset/chapter3/TrailingCommaFixTest.kt",
    "content": "package com.saveourtool.diktat.ruleset.chapter3\n\nimport com.saveourtool.diktat.common.config.rules.DIKTAT_COMMON\nimport com.saveourtool.diktat.common.config.rules.RulesConfig\nimport com.saveourtool.diktat.ruleset.constants.Warnings\nimport com.saveourtool.diktat.ruleset.rules.chapter3.TrailingCommaRule\nimport com.saveourtool.diktat.util.FixTestBase\n\nimport generated.WarningNames\nimport org.junit.jupiter.api.Disabled\nimport org.junit.jupiter.api.Tag\nimport org.junit.jupiter.api.Test\n\nclass TrailingCommaFixTest : FixTestBase(\"test/paragraph3/trailing_comma\", ::TrailingCommaRule) {\n    private val config: List<RulesConfig> = listOf(\n        RulesConfig(\n            Warnings.TRAILING_COMMA.name, true,\n            mapOf(\"valueArgument\" to \"true\",\n                \"valueParameter\" to \"true\",\n                \"indices\" to \"true\",\n                \"whenConditions\" to \"true\",\n                \"collectionLiteral\" to \"true\",\n                \"typeArgument\" to \"true\",\n                \"typeParameter\" to \"true\",\n                \"destructuringDeclaration\" to \"true\")),\n        RulesConfig(\n            DIKTAT_COMMON, true,\n            mapOf(\"kotlinVersion\" to \"1.4.21\"))\n    )\n\n    @Test\n    @Tag(WarningNames.TRAILING_COMMA)\n    fun `should add all trailing comma`() {\n        fixAndCompare(\"TrailingCommaExpected.kt\", \"TrailingCommaTest.kt\", config)\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/test/kotlin/com/saveourtool/diktat/ruleset/chapter3/TrailingCommaWarnTest.kt",
    "content": "package com.saveourtool.diktat.ruleset.chapter3\n\nimport com.saveourtool.diktat.common.config.rules.DIKTAT_RULE_SET_ID\nimport com.saveourtool.diktat.common.config.rules.RulesConfig\nimport com.saveourtool.diktat.ruleset.constants.Warnings.TRAILING_COMMA\nimport com.saveourtool.diktat.ruleset.rules.chapter3.TrailingCommaRule\nimport com.saveourtool.diktat.util.LintTestBase\n\nimport com.saveourtool.diktat.api.DiktatError\nimport generated.WarningNames\nimport org.junit.jupiter.api.Tag\nimport org.junit.jupiter.api.Test\n\nclass TrailingCommaWarnTest : LintTestBase(::TrailingCommaRule) {\n    private val ruleId = \"$DIKTAT_RULE_SET_ID:${TrailingCommaRule.NAME_ID}\"\n\n    private fun getRulesConfig(paramName: String): List<RulesConfig> = listOf(\n        RulesConfig(\n            TRAILING_COMMA.name, true,\n            mapOf(paramName to \"true\"))\n    )\n\n    @Test\n    @Tag(WarningNames.TRAILING_COMMA)\n    fun `check value arguments`() {\n        lintMethod(\n            \"\"\"\n                fun shift(x: Int, y: Int) {\n                    shift(\n                        25,\n                        20 // trailing comma\n                    )\n\n                    val colors = listOf(\n                        \"red\",\n                        \"green\",\n                        \"blue\" // trailing comma\n                    )\n                }\n            \"\"\".trimMargin(),\n            DiktatError(4, 25, ruleId, \"${TRAILING_COMMA.warnText()} after VALUE_ARGUMENT: 20\", true),\n            DiktatError(10, 25, ruleId, \"${TRAILING_COMMA.warnText()} after VALUE_ARGUMENT: \\\"blue\\\"\", true),\n            rulesConfigList = getRulesConfig(\"valueArgument\")\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.TRAILING_COMMA)\n    fun `check class properties and parameters`() {\n        lintMethod(\n            \"\"\"\n                class Customer(\n                    val name: String,\n                    val lastName: String // trailing comma\n                )\n\n                class Customer(\n                    val name: String,\n                    lastName: String // trailing comma\n                )\n            \"\"\".trimMargin(),\n            DiktatError(3, 21, ruleId, \"${TRAILING_COMMA.warnText()} after VALUE_PARAMETER: val lastName: String // trailing comma\", true),\n            DiktatError(8, 21, ruleId, \"${TRAILING_COMMA.warnText()} after VALUE_PARAMETER: lastName: String // trailing comma\", true),\n            rulesConfigList = getRulesConfig(\"valueParameter\")\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.TRAILING_COMMA)\n    fun `check function value parameters`() {\n        lintMethod(\n            \"\"\"\n                class A {\n\n                    fun foo() {}\n\n                    fun powerOf(\n                        number: Int,\n                        exponent: Int, // trailing comma\n                    ) { /*...*/ }\n\n                    constructor(\n                        x: Comparable<Number>,\n                        y: Iterable<Number>\n                    ) {}\n\n                    fun print(\n                        vararg quantity: Int,\n                        description: String\n                    ) {}\n                }\n            \"\"\".trimMargin(),\n            DiktatError(12, 25, ruleId, \"${TRAILING_COMMA.warnText()} after VALUE_PARAMETER: y: Iterable<Number>\", true),\n            DiktatError(17, 25, ruleId, \"${TRAILING_COMMA.warnText()} after VALUE_PARAMETER: description: String\", true),\n            rulesConfigList = getRulesConfig(\"valueParameter\")\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.TRAILING_COMMA)\n    fun `check parameters with optional type`() {\n        lintMethod(\n            \"\"\"\n                fun foo() {\n                    val sum: (Int, Int, Int,) -> Int = fun(\n                        x,\n                        y,\n                        z // trailing comma\n                    ): Int {\n                        return x + y + x\n                    }\n                    println(sum(8, 8, 8))\n                }\n            \"\"\".trimMargin(),\n            DiktatError(5, 25, ruleId, \"${TRAILING_COMMA.warnText()} after VALUE_PARAMETER: z // trailing comma\", true),\n            rulesConfigList = getRulesConfig(\"valueParameter\")\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.TRAILING_COMMA)\n    fun `check indexing suffix`() {\n        lintMethod(\n            \"\"\"\n                class Surface {\n                    operator fun get(x: Int, y: Int) = 2 * x + 4 * y - 10\n                }\n                fun getZValue(mySurface: Surface, xValue: Int, yValue: Int) =\n                    mySurface[\n                        xValue,\n                        yValue // trailing comma\n                    ]\n            \"\"\".trimMargin(),\n            DiktatError(7, 25, ruleId, \"${TRAILING_COMMA.warnText()} after REFERENCE_EXPRESSION: yValue\", true),\n            rulesConfigList = getRulesConfig(\"referenceExpression\")\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.TRAILING_COMMA)\n    fun `check lambda parameters`() {\n        lintMethod(\n            \"\"\"\n                fun main() {\n                    val x = {\n                            x: Comparable<Number>,\n                            y: Iterable<Number>\n                            -> println(\"1\",)\n                    }\n\n                    println(x,)\n                }\n            \"\"\".trimMargin(),\n            rulesConfigList = getRulesConfig(\"valueParameter\")\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.TRAILING_COMMA)\n    fun `check when entry`() {\n        lintMethod(\n            \"\"\"\n                fun isReferenceApplicable(myReference: KClass<*>) = when (myReference) {\n                    Comparable::class,\n                    Iterable::class,\n                    String::class // trailing comma\n                        -> true\n                    else -> false\n                }\n\n                fun someFun() {\n                   when (x) {\n                       is Int,\n                       is String\n                            -> print((x as Int).length)\n                       is Long, -> x as Int\n                   }\n               }\n\n               fun someFun() {\n                   when (x) {\n                       in 1..2\n                        -> foo()\n                   }\n               }\n\n               fun someFun() {\n                   when (x) {}\n               }\n            \"\"\".trimMargin(),\n            DiktatError(4, 21, ruleId, \"${TRAILING_COMMA.warnText()} after WHEN_CONDITION_WITH_EXPRESSION: String::class\", true),\n            DiktatError(12, 24, ruleId, \"${TRAILING_COMMA.warnText()} after WHEN_CONDITION_IS_PATTERN: is String\", true),\n            DiktatError(20, 24, ruleId, \"${TRAILING_COMMA.warnText()} after WHEN_CONDITION_IN_RANGE: in 1..2\", true),\n            rulesConfigList = getRulesConfig(\"whenConditions\")\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.TRAILING_COMMA)\n    fun `check collection literals`() {\n        lintMethod(\n            \"\"\"\n                annotation class ApplicableFor(val services: Array<String>)\n\n                @ApplicableFor([\n                    \"serializer\",\n                    \"balancer\",\n                    \"database\",\n                    \"inMemoryCache\" // trailing comma\n                ],)\n                fun foo() {}\n            \"\"\".trimMargin(),\n            DiktatError(7, 21, ruleId, \"${TRAILING_COMMA.warnText()} after STRING_TEMPLATE: \\\"inMemoryCache\\\"\", true),\n            rulesConfigList = getRulesConfig(\"collectionLiteral\")\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.TRAILING_COMMA)\n    fun `check type arguments`() {\n        lintMethod(\n            \"\"\"\n                fun <T1, T21,> foo() {}\n\n                fun main() {\n                    foo<\n                            Comparable<Number,>,\n                            Iterable<Number\n                            > // trailing comma\n                            >()\n                }\n            \"\"\".trimMargin(),\n            DiktatError(6, 29, ruleId, \"${TRAILING_COMMA.warnText()} after TYPE_PROJECTION: Iterable<Number...\", true),\n            DiktatError(6, 38, ruleId, \"${TRAILING_COMMA.warnText()} after TYPE_PROJECTION: Number\", true),\n            rulesConfigList = getRulesConfig(\"typeArgument\")\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.TRAILING_COMMA)\n    fun `check type parameters`() {\n        lintMethod(\n            \"\"\"\n                class MyMap<\n                        MyKey,\n                        MyValue // trailing comma\n                        > {}\n            \"\"\".trimMargin(),\n            DiktatError(3, 25, ruleId, \"${TRAILING_COMMA.warnText()} after TYPE_PARAMETER: MyValue\", true),\n            rulesConfigList = getRulesConfig(\"typeParameter\")\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.TRAILING_COMMA)\n    fun `check destructuring declarations`() {\n        lintMethod(\n            \"\"\"\n                fun foo() {\n                    data class Car(val manufacturer: String, val model: String, val year: Int)\n                    val myCar = Car(\"Tesla\", \"Y\", 2019)\n\n                    val (\n                        manufacturer,\n                        model,\n                        year // trailing comma\n                    ) = myCar\n\n                    val cars = listOf<Car>()\n                    fun printMeanValue() {\n                        var meanValue: Int = 0\n                        for ((\n                            _,\n                            _,\n                            year // trailing comma\n                        ) in cars) {\n                            meanValue += year\n                        }\n                        println(meanValue/cars.size)\n                    }\n                    printMeanValue()\n                }\n            \"\"\".trimMargin(),\n            DiktatError(8, 25, ruleId, \"${TRAILING_COMMA.warnText()} after DESTRUCTURING_DECLARATION_ENTRY: year\", true),\n            DiktatError(17, 29, ruleId, \"${TRAILING_COMMA.warnText()} after DESTRUCTURING_DECLARATION_ENTRY: year\", true),\n            rulesConfigList = getRulesConfig(\"destructuringDeclaration\")\n        )\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/test/kotlin/com/saveourtool/diktat/ruleset/chapter3/WhenMustHaveElseFixTest.kt",
    "content": "package com.saveourtool.diktat.ruleset.chapter3\n\nimport com.saveourtool.diktat.ruleset.rules.chapter3.WhenMustHaveElseRule\nimport com.saveourtool.diktat.util.FixTestBase\n\nimport generated.WarningNames\nimport org.junit.jupiter.api.Tag\nimport org.junit.jupiter.api.Test\n\nclass WhenMustHaveElseFixTest : FixTestBase(\"test/paragraph3/else_expected\", ::WhenMustHaveElseRule) {\n    @Test\n    @Tag(WarningNames.WHEN_WITHOUT_ELSE)\n    fun `should make else branch`() {\n        fixAndCompare(\"ElseInWhenExpected.kt\", \"ElseInWhenTest.kt\")\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/test/kotlin/com/saveourtool/diktat/ruleset/chapter3/WhenMustHaveElseWarnTest.kt",
    "content": "package com.saveourtool.diktat.ruleset.chapter3\n\nimport com.saveourtool.diktat.common.config.rules.DIKTAT_RULE_SET_ID\nimport com.saveourtool.diktat.ruleset.constants.Warnings\nimport com.saveourtool.diktat.ruleset.rules.chapter3.WhenMustHaveElseRule\nimport com.saveourtool.diktat.util.LintTestBase\n\nimport com.saveourtool.diktat.api.DiktatError\nimport generated.WarningNames\nimport org.junit.jupiter.api.Tag\nimport org.junit.jupiter.api.Test\n\nclass WhenMustHaveElseWarnTest : LintTestBase(::WhenMustHaveElseRule) {\n    private val ruleId = \"$DIKTAT_RULE_SET_ID:${WhenMustHaveElseRule.NAME_ID}\"\n\n    @Test\n    @Tag(WarningNames.WHEN_WITHOUT_ELSE)\n    fun `when in func test good`() {\n        lintMethod(\n            \"\"\"\n                    |fun foo() {\n                    |    when(a) {\n                    |       1 -> print(\"x is neither 1 nor 2\")\n                    |       else -> {}\n                    |    }\n                    |}\n            \"\"\".trimMargin()\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.WHEN_WITHOUT_ELSE)\n    fun `when in func test bad`() {\n        lintMethod(\n            \"\"\"\n                    |fun foo() {\n                    |    when(a) {\n                    |       1 -> print(\"x is neither 1 nor 2\")\n                    |    }\n                    |}\n                    |\n            \"\"\".trimMargin(),\n            DiktatError(2, 5, ruleId, \"${Warnings.WHEN_WITHOUT_ELSE.warnText()} else was not found\", true)\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.WHEN_WITHOUT_ELSE)\n    fun `when expression in func test good`() {\n        lintMethod(\n            \"\"\"\n                    |fun foo() {\n                    |    val obj = when(a) {\n                    |       1 -> print(\"x is neither 1 nor 2\")\n                    |    }\n                    |}\n            \"\"\".trimMargin()\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.WHEN_WITHOUT_ELSE)\n    fun `when expression in func test good 2`() {\n        lintMethod(\n            \"\"\"\n                    |fun foo() {\n                    |    val x = listOf<Int>().map {\n                    |           when(it) {\n                    |               1 -> it * 2\n                    |           }\n                    |    }\n                    |}\n            \"\"\".trimMargin()\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.WHEN_WITHOUT_ELSE)\n    fun `regression - shouldn't check when in when branches and assignments`() {\n        lintMethod(\n            \"\"\"\n                    |fun foo() {\n                    |    var x: Int\n                    |    x = when(it) {\n                    |        1 -> when (x) {\n                    |            2 -> foo()\n                    |        }\n                    |    }\n                    |}\n            \"\"\".trimMargin()\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.WHEN_WITHOUT_ELSE)\n    fun `when in func only enum entries`() {\n        lintMethod(\n            \"\"\"\n                |fun foo() {\n                |    val v: Enum\n                |    when (v) {\n                |        Enum.ONE, Enum.TWO -> foo()\n                |        Enum.THREE -> bar()\n                |        in Enum.FOUR..Enum.TEN -> boo()\n                |        ELEVEN -> anotherFoo()\n                |        in TWELVE..Enum.TWENTY -> anotherBar()\n                |    }\n                |}\n            \"\"\".trimMargin()\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.WHEN_WITHOUT_ELSE)\n    fun `when in func not only enum entries`() {\n        lintMethod(\n            \"\"\"\n                |fun foo() {\n                |    val v: Enum\n                |    when (v) {\n                |        Enum.ONE -> foo()\n                |        f(Enum.TWO) -> bar()\n                |    }\n                |}\n            \"\"\".trimMargin(),\n            DiktatError(3, 5, ruleId, \"${Warnings.WHEN_WITHOUT_ELSE.warnText()} else was not found\", true)\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.WHEN_WITHOUT_ELSE)\n    fun `when in func not only enum entries but in ranges`() {\n        lintMethod(\n            \"\"\"\n                |fun foo() {\n                |    val v: Enum\n                |    when (v) {\n                |        Enum.ONE -> foo()\n                |        in 1..5 -> bar()\n                |    }\n                |}\n            \"\"\".trimMargin(),\n            DiktatError(3, 5, ruleId, \"${Warnings.WHEN_WITHOUT_ELSE.warnText()} else was not found\", true)\n        )\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/test/kotlin/com/saveourtool/diktat/ruleset/chapter3/files/BlankLinesFixTest.kt",
    "content": "package com.saveourtool.diktat.ruleset.chapter3.files\n\nimport com.saveourtool.diktat.ruleset.rules.chapter3.files.BlankLinesRule\nimport com.saveourtool.diktat.util.FixTestBase\n\nimport generated.WarningNames\nimport org.junit.jupiter.api.Tag\nimport org.junit.jupiter.api.Test\n\nclass BlankLinesFixTest : FixTestBase(\"test/paragraph3/blank_lines\", ::BlankLinesRule) {\n    @Test\n    @Tag(WarningNames.TOO_MANY_BLANK_LINES)\n    fun `should remove redundant blank lines`() {\n        fixAndCompare(\"RedundantBlankLinesExpected.kt\", \"RedundantBlankLinesTest.kt\")\n    }\n\n    @Test\n    @Tag(WarningNames.TOO_MANY_BLANK_LINES)\n    fun `should remove blank lines in the beginning and at the end of code block`() {\n        fixAndCompare(\"CodeBlockWithBlankLinesExpected.kt\", \"CodeBlockWithBlankLinesTest.kt\")\n    }\n\n    @Test\n    @Tag(WarningNames.TOO_MANY_BLANK_LINES)\n    fun `should remove empty line before the closing quote`() {\n        fixAndCompare(\"RedundantBlankLinesAtTheEndOfBlockExpected.kt\", \"RedundantBlankLinesAtTheEndOfBlockTest.kt\")\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/test/kotlin/com/saveourtool/diktat/ruleset/chapter3/files/BlankLinesWarnTest.kt",
    "content": "package com.saveourtool.diktat.ruleset.chapter3.files\n\nimport com.saveourtool.diktat.common.config.rules.DIKTAT_RULE_SET_ID\nimport com.saveourtool.diktat.ruleset.constants.Warnings.TOO_MANY_BLANK_LINES\nimport com.saveourtool.diktat.ruleset.rules.chapter3.files.BlankLinesRule\nimport com.saveourtool.diktat.util.LintTestBase\n\nimport com.saveourtool.diktat.api.DiktatError\nimport generated.WarningNames\nimport org.junit.jupiter.api.Tag\nimport org.junit.jupiter.api.Test\n\nclass BlankLinesWarnTest : LintTestBase(::BlankLinesRule) {\n    private val ruleId = \"$DIKTAT_RULE_SET_ID:${BlankLinesRule.NAME_ID}\"\n    private val consecutiveLinesWarn = \"${TOO_MANY_BLANK_LINES.warnText()} do not use more than two consecutive blank lines\"\n    private fun blankLinesInBlockWarn(isBeginning: Boolean) =\n        \"${TOO_MANY_BLANK_LINES.warnText()} do not put newlines ${if (isBeginning) \"in the beginning\" else \"at the end\"} of code blocks\"\n\n    @Test\n    @Tag(WarningNames.TOO_MANY_BLANK_LINES)\n    fun `blank lines usage - positive example`() {\n        lintMethod(\n            \"\"\"\n                    |class Example {\n                    |    fun foo() {\n                    |\n                    |    }\n                    |}\n            \"\"\".trimMargin()\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.TOO_MANY_BLANK_LINES)\n    fun `check lambda with empty block`() {\n        lintMethod(\n            \"\"\"\n                    |fun foo() {\n                    |   run {\n                    |\n                    |   }\n                    |}\n            \"\"\".trimMargin()\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.TOO_MANY_BLANK_LINES)\n    fun `should prohibit usage of two or more consecutive blank lines`() {\n        lintMethod(\n            \"\"\"\n                    |class Example {\n                    |\n                    |\n                    |    val foo = 0\n                    |\n                    |\n                    |    fun bar() { }\n                    |}\n            \"\"\".trimMargin(),\n            DiktatError(1, 16, ruleId, consecutiveLinesWarn, true),\n            DiktatError(4, 16, ruleId, consecutiveLinesWarn, true)\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.TOO_MANY_BLANK_LINES)\n    fun `should prohibit blank lines in the beginning and at the end of code block`() {\n        lintMethod(\n            \"\"\"\n                    |class Example {\n                    |\n                    |    fun foo() {\n                    |\n                    |        bar()\n                    |\n                    |    }\n                    |}\n            \"\"\".trimMargin(),\n            DiktatError(1, 16, ruleId, blankLinesInBlockWarn(true), true),\n            DiktatError(3, 16, ruleId, blankLinesInBlockWarn(true), true),\n            DiktatError(5, 14, ruleId, blankLinesInBlockWarn(false), true)\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.TOO_MANY_BLANK_LINES)\n    fun `should prohibit empty line before the closing quote`() {\n        lintMethod(\n            \"\"\"\n                    |class Example {\n                    |    fun foo() {\n                    |        bar()\n                    |\n                    |    }\n                    |\n                    |}\n            \"\"\".trimMargin(),\n            DiktatError(3, 14, ruleId, blankLinesInBlockWarn(false), true),\n            DiktatError(5, 6, ruleId, blankLinesInBlockWarn(false), true)\n        )\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/test/kotlin/com/saveourtool/diktat/ruleset/chapter3/files/NewlinesRuleFixTest.kt",
    "content": "package com.saveourtool.diktat.ruleset.chapter3.files\n\nimport com.saveourtool.diktat.common.config.rules.RulesConfig\nimport com.saveourtool.diktat.ruleset.constants.Warnings\nimport com.saveourtool.diktat.ruleset.rules.chapter3.files.NewlinesRule\nimport com.saveourtool.diktat.util.FixTestBase\n\nimport generated.WarningNames\nimport org.junit.jupiter.api.Tag\nimport org.junit.jupiter.api.Test\n\nclass NewlinesRuleFixTest : FixTestBase(\"test/paragraph3/newlines\", ::NewlinesRule) {\n    private val rulesConfigListShort: List<RulesConfig> = listOf(\n        RulesConfig(Warnings.WRONG_NEWLINES.name, true,\n            mapOf(\"maxCallsInOneLine\" to \"1\"))\n    )\n\n    @Test\n    @Tag(WarningNames.WRONG_NEWLINES)\n    fun `should fix newlines near operators`() {\n        fixAndCompare(\"OperatorsExpected.kt\", \"OperatorsTest.kt\")\n    }\n\n    @Test\n    @Tag(WarningNames.WRONG_NEWLINES)\n    fun `should fix newlines to follow functional style`() {\n        fixAndCompare(\"FunctionalStyleExpected.kt\", \"FunctionalStyleTest.kt\", rulesConfigListShort)\n    }\n\n    @Test\n    @Tag(WarningNames.WRONG_NEWLINES)\n    fun `should fix empty space between identifier and opening parentheses`() {\n        fixAndCompare(\"LParExpected.kt\", \"LParTest.kt\")\n    }\n\n    @Test\n    @Tag(WarningNames.WRONG_NEWLINES)\n    fun `should fix wrong newlines around comma`() {\n        fixAndCompare(\"CommaExpected.kt\", \"CommaTest.kt\")\n    }\n\n    @Test\n    @Tag(WarningNames.WRONG_NEWLINES)\n    fun `should fix wrong newlines before colon`() {\n        fixAndCompare(\"ColonExpected.kt\", \"ColonTest.kt\")\n    }\n\n    @Test\n    @Tag(WarningNames.WRONG_NEWLINES)\n    fun `One line parameters list sheet must contain no more than 2 parameters`() {\n        fixAndCompare(\"SizeParameterListExpected.kt\", \"SizeParameterListTest.kt\")\n    }\n\n    @Test\n    @Tag(WarningNames.WRONG_NEWLINES)\n    fun `should fix wrong newlines in lambdas`() {\n        fixAndCompare(\"LambdaExpected.kt\", \"LambdaTest.kt\")\n    }\n\n    @Test\n    @Tag(WarningNames.WRONG_NEWLINES)\n    fun `should replace functions with only return with expression body`() {\n        fixAndCompare(\"ExpressionBodyExpected.kt\", \"ExpressionBodyTest.kt\")\n    }\n\n    @Test\n    @Tag(WarningNames.WRONG_NEWLINES)\n    fun `should insert newlines in a long parameter or supertype list`() {\n        fixAndCompare(\"ParameterListExpected.kt\", \"ParameterListTest.kt\")\n    }\n\n    @Test\n    @Tag(WarningNames.WRONG_NEWLINES)\n    fun `should insert newlines in supertype list`() {\n        fixAndCompare(\"SuperClassListOnTheSameLineExpected.kt\", \"SuperClassListOnTheSameLineTest.kt\")\n    }\n\n    @Test\n    @Tag(WarningNames.WRONG_NEWLINES)\n    fun `should fix one line function`() {\n        fixAndCompare(\"OneLineFunctionExpected.kt\", \"OneLineFunctionTest.kt\")\n    }\n\n    @Test\n    @Tag(WarningNames.WRONG_NEWLINES)\n    fun `list argument in lambda`() {\n        fixAndCompare(\"ListArgumentLambdaExpected.kt\", \"ListArgumentLambdaTest.kt\")\n    }\n\n    @Test\n    @Tag(WarningNames.WRONG_NEWLINES)\n    fun `long dot qualified expression`() {\n        fixAndCompare(\"LongDotQualifiedExpressionExpected.kt\", \"LongDotQualifiedExpressionTest.kt\")\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/test/kotlin/com/saveourtool/diktat/ruleset/chapter3/files/NewlinesRuleWarnTest.kt",
    "content": "package com.saveourtool.diktat.ruleset.chapter3.files\n\nimport com.saveourtool.diktat.common.config.rules.DIKTAT_RULE_SET_ID\nimport com.saveourtool.diktat.common.config.rules.RulesConfig\nimport com.saveourtool.diktat.ruleset.constants.Warnings.COMPLEX_EXPRESSION\nimport com.saveourtool.diktat.ruleset.constants.Warnings.WRONG_NEWLINES\nimport com.saveourtool.diktat.ruleset.rules.chapter3.files.NewlinesRule\nimport com.saveourtool.diktat.util.LintTestBase\n\nimport com.saveourtool.diktat.api.DiktatError\nimport generated.WarningNames\nimport org.junit.jupiter.api.Disabled\nimport org.junit.jupiter.api.Tag\nimport org.junit.jupiter.api.Tags\nimport org.junit.jupiter.api.Test\nimport org.junit.jupiter.api.io.TempDir\nimport java.nio.file.Path\n\n@Suppress(\"LargeClass\")\nclass NewlinesRuleWarnTest : LintTestBase(::NewlinesRule) {\n    private val rulesConfigList: List<RulesConfig> = listOf(\n        RulesConfig(WRONG_NEWLINES.name, true,\n            mapOf(\"maxCallsInOneLine\" to \"3\"))\n    )\n    private val rulesConfigListShort: List<RulesConfig> = listOf(\n        RulesConfig(WRONG_NEWLINES.name, true,\n            mapOf(\"maxCallsInOneLine\" to \"1\"))\n    )\n    private val rulesConfigListLong: List<RulesConfig> = listOf(\n        RulesConfig(WRONG_NEWLINES.name, true,\n            mapOf(\"maxCallsInOneLine\" to \"10\"))\n    )\n    private val ruleId = \"$DIKTAT_RULE_SET_ID:${NewlinesRule.NAME_ID}\"\n    private val dotQuaOrSafeAccessOrPostfixExpression = \"${WRONG_NEWLINES.warnText()} wrong split long `dot qualified expression` or `safe access expression`\"\n    private val shouldBreakAfter = \"${WRONG_NEWLINES.warnText()} should break a line after and not before\"\n    private val shouldBreakBefore = \"${WRONG_NEWLINES.warnText()} should break a line before and not after\"\n    private val functionalStyleWarn = \"${WRONG_NEWLINES.warnText()} should follow functional style at\"\n    private val lparWarn = \"${WRONG_NEWLINES.warnText()} opening parentheses should not be separated from constructor or function name\"\n    private val commaWarn = \"${WRONG_NEWLINES.warnText()} newline should be placed only after comma\"\n    private val prevColonWarn = \"${WRONG_NEWLINES.warnText()} newline shouldn't be placed before colon\"\n    private val lambdaWithArrowWarn = \"${WRONG_NEWLINES.warnText()} in lambda with several lines in body newline should be placed after an arrow\"\n    private val lambdaWithoutArrowWarn = \"${WRONG_NEWLINES.warnText()} in lambda with several lines in body newline should be placed after an opening brace\"\n    private val singleReturnWarn = \"${WRONG_NEWLINES.warnText()} functions with single return statement should be simplified to expression body\"\n\n    @Test\n    @Tag(WarningNames.WRONG_NEWLINES)\n    fun `should not false positively trigger on dots in package directive and imports`() {\n        lintMethod(\n            \"\"\"\n                    |package com.saveourtool.diktat.example\n                    |\n                    |import com.saveourtool.diktat.Foo\n                    |import com.saveourtool.diktat.example.*\n            \"\"\".trimMargin()\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.WRONG_NEWLINES)\n    fun `should not false positively trigger on operators in the middle of the line`() {\n        lintMethod(\n            \"\"\"\n                    |fun foo() {\n                    |    val log = LoggerFactory.getLogger(Foo::class.java)\n                    |    val c = c1 && c2\n                    |    obj.foo()\n                    |    obj?.foo()\n                    |    obj::foo\n                    |    bar().let(::baz)\n                    |    ::baz\n                    |}\n            \"\"\".trimMargin()\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.WRONG_NEWLINES)\n    fun `line breaking at operators - positive example`() {\n        lintMethod(\n            \"\"\"\n                    |fun foo() {\n                    |    val foo: Foo? = bar ?: Bar(javaClass.classLoader).readResource(\"baz\")\n                    |    foo?: bar\n                    |\n                    |    val and = condition1 &&\n                    |        condition2\n                    |    val plus = x +\n                    |        y\n                    |\n                    |    obj!!\n                    |\n                    |    obj\n                    |        .foo()\n                    |    obj\n                    |        ?.foo()\n                    |    obj\n                    |        ?: OBJ\n                    |    obj\n                    |        ::foo\n                    |}\n            \"\"\".trimMargin()\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.WRONG_NEWLINES)\n    fun `line breaking at operators`() {\n        lintMethod(\n            \"\"\"\n                    |fun foo() {\n                    |    val and = condition1\n                    |        && condition2\n                    |    // this isn't an expression\n                    |    val plus = x\n                    |        + y\n                    |\n                    |    obj.\n                    |        foo()\n                    |    obj?.\n                    |        foo()\n                    |    obj ?:\n                    |        OBJ\n                    |    obj::\n                    |        foo\n                    |}\n            \"\"\".trimMargin(),\n            DiktatError(3, 9, ruleId, \"$shouldBreakAfter &&\", true),\n            DiktatError(8, 8, ruleId, \"$shouldBreakBefore .\", true),\n            DiktatError(10, 8, ruleId, \"$shouldBreakBefore ?.\", true),\n            DiktatError(12, 9, ruleId, \"$shouldBreakBefore ?:\", true),\n            DiktatError(14, 8, ruleId, \"$shouldBreakBefore ::\", true)\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.WRONG_NEWLINES)\n    fun `line breaking after infix functions - positive example`() {\n        lintMethod(\n            \"\"\"\n                    |fun foo() {\n                    |    true xor\n                    |        false\n                    |\n                    |    true\n                    |        .xor(false)\n                    |\n                    |    (true xor\n                    |        false)\n                    |\n                    |    true xor false or true\n                    |}\n            \"\"\".trimMargin()\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.WRONG_NEWLINES)\n    fun `line breaking after infix functions`() {\n        lintMethod(\n            \"\"\"\n                    |fun foo() {\n                    |    (true\n                    |        xor false)\n                    |\n                    |    (true\n                    |        xor\n                    |        false)\n                    |}\n            \"\"\".trimMargin(),\n            DiktatError(3, 9, ruleId, \"$shouldBreakAfter xor\", true),\n            DiktatError(6, 9, ruleId, \"$shouldBreakAfter xor\", true)\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.WRONG_NEWLINES)\n    fun `line breaking after infix functions - several functions in a chain`() {\n        lintMethod(\n            \"\"\"\n                    |fun foo() {\n                    |    (true xor false\n                    |        or true\n                    |    )\n                    |\n                    |    (true\n                    |        xor false\n                    |        or true\n                    |    )\n                    |\n                    |    (true\n                    |        xor\n                    |        false\n                    |        or\n                    |        true\n                    |    )\n                    |}\n            \"\"\".trimMargin(),\n            DiktatError(3, 9, ruleId, \"$shouldBreakAfter or\", true),\n            DiktatError(7, 9, ruleId, \"$shouldBreakAfter xor\", true),\n            DiktatError(8, 9, ruleId, \"$shouldBreakAfter or\", true),\n            DiktatError(12, 9, ruleId, \"$shouldBreakAfter xor\", true),\n            DiktatError(14, 9, ruleId, \"$shouldBreakAfter or\", true)\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.WRONG_NEWLINES)\n    fun `chained calls should follow functional style - positive example`() {\n        lintMethod(\n            \"\"\"\n                    |fun foo(list: List<Bar>?) {\n                    |    list!!\n                    |        .filterNotNull()\n                    |        .map { it.baz() }\n                    |        .firstOrNull {\n                    |            it.condition()\n                    |        }\n                    |        ?.qux()\n                    |}\n            \"\"\".trimMargin()\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.WRONG_NEWLINES)\n    fun `chained calls should follow functional style - should not trigger on single dot calls`() {\n        lintMethod(\n            \"\"\"\n                    |fun foo(bar: Bar?) {\n                    |    bar.baz()\n                    |    bar?.baz()\n                    |    bar!!.baz()\n                    |}\n            \"\"\".trimMargin()\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.WRONG_NEWLINES)\n    fun `chained calls should follow functional style`() {\n        lintMethod(\n            \"\"\"\n                    |fun foo(list: List<Bar>?) {\n                    |    list!!.filterNotNull()\n                    |        .map { it.baz() }.firstOrNull {\n                    |            it.condition()\n                    |        }?.qux()\n                    |}\n            \"\"\".trimMargin(),\n            DiktatError(2, 5, ruleId, dotQuaOrSafeAccessOrPostfixExpression, true),\n            DiktatError(2, 11, ruleId, \"$functionalStyleWarn .\", true),\n            DiktatError(3, 26, ruleId, \"$functionalStyleWarn .\", true),\n            DiktatError(5, 10, ruleId, \"$functionalStyleWarn ?.\", true),\n            rulesConfigList = rulesConfigListShort\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.WRONG_NEWLINES)\n    fun `chained calls should follow functional style - exception for ternary if-else`() {\n        lintMethod(\n            \"\"\"\n                    |fun foo(list: List<Bar>?) {\n                    |    if (list.size > n) list.filterNotNull().map { it.baz() } else list.let { it.bar() }.firstOrNull()?.qux()\n                    |}\n            \"\"\".trimMargin()\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.WRONG_NEWLINES)\n    fun `newline should be placed only after assignment operator`() {\n        lintMethod(\n            \"\"\"\n                    |class Example {\n                    |    val a =\n                    |        42\n                    |    val b\n                    |        = 43\n                    |}\n            \"\"\".trimMargin(),\n            DiktatError(5, 9, ruleId, \"$shouldBreakAfter =\", true)\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.WRONG_NEWLINES)\n    fun `newline should be placed only after comma`() {\n        lintMethod(\n            \"\"\"\n                    |fun foo(a: Int\n                    |        ,\n                    |        b: Int) {\n                    |    bar(a\n                    |        , b)\n                    |}\n            \"\"\".trimMargin(),\n            DiktatError(2, 9, ruleId, commaWarn, true),\n            DiktatError(5, 9, ruleId, commaWarn, true)\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.WRONG_NEWLINES)\n    fun `newline shouldn't be placed before colon`() {\n        lintMethod(\n            \"\"\"\n                    |fun foo(a\n                    |        : Int,\n                    |        b\n                    |        : Int) {\n                    |    bar(a, b)\n                    |}\n            \"\"\".trimMargin(),\n            DiktatError(2, 9, ruleId, prevColonWarn, true),\n            DiktatError(4, 9, ruleId, prevColonWarn, true)\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.WRONG_NEWLINES)\n    fun `One line parameters list sheet must contain no more than 2 parameters`() {\n        lintMethod(\n            \"\"\"\n                    |fun foo(a: Int, b: Int, c: Int) {\n                    |      bar(a, b)\n                    |}\n            \"\"\".trimMargin(),\n            DiktatError(1, 8, ruleId, \"${WRONG_NEWLINES.warnText()} first parameter should be placed on a separate line or all other parameters \" +\n                    \"should be aligned with it in declaration of <foo>\", true),\n            DiktatError(1, 8, ruleId, \"${WRONG_NEWLINES.warnText()} value parameters should be placed on different lines in declaration of <foo>\", true)\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.WRONG_NEWLINES)\n    fun `newline after colon`() {\n        lintMethod(\n            \"\"\"\n                    |fun foo(a:\n                    |      Int,\n                    |      b:\n                    |      Int) {\n                    |      bar(a, b)\n                    |}\n            \"\"\".trimMargin()\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.WRONG_NEWLINES)\n    fun `list parameter should be placed on different lines`() {\n        lintMethod(\n            \"\"\"\n                    |fun foo(\n                    |      a: Int,\n                    |      b: Int,\n                    |      c: Int\n                    |      ) {\n                    |}\n            \"\"\".trimMargin(),\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.WRONG_NEWLINES)\n    fun `function name should not be separated from ( - positive example`() {\n        lintMethod(\n            \"\"\"\n                    |val foo = Foo(arg1, arg2)\n                    |class Example(\n                    |    val x: Int\n                    |) {\n                    |    fun foo(\n                    |        a: Int\n                    |    ) { }\n                    |}\n            \"\"\".trimMargin()\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.WRONG_NEWLINES)\n    fun `function name should not be separated from ( - should not trigger on other parenthesis`() {\n        lintMethod(\n            \"\"\"\n                    |val x = (2 + 2) * 2\n                    |val y = if (condition) 2 else 1\n                    |fun foo(f: (Int) -> Pair<Int, Int>) {\n                    |    val (a, b) = f(0)\n                    |}\n                    |fun bar(f: (x: Int) -> Unit) { }\n            \"\"\".trimMargin()\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.WRONG_NEWLINES)\n    fun `function name should not be separated from (`() {\n        lintMethod(\n            \"\"\"\n                    |val foo = Foo  (arg1, arg2)\n                    |class Example\n                    |    (\n                    |        val x: Int\n                    |    ) {\n                    |    fun foo\n                    |    (\n                    |        a: Int\n                    |    ) { }\n                    |}\n            \"\"\".trimMargin(),\n            DiktatError(1, 16, ruleId, lparWarn, true),\n            DiktatError(3, 5, ruleId, lparWarn, true),\n            DiktatError(7, 5, ruleId, lparWarn, true)\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.WRONG_NEWLINES)\n    fun `newline should be placed only after comma - positive example`() {\n        lintMethod(\n            \"\"\"\n                    |fun foo(a: Int,\n                    |        b: Int) {\n                    |    bar(a, b)\n                    |}\n            \"\"\".trimMargin()\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.WRONG_NEWLINES)\n    fun `in lambdas newline should be placed after an arrow - positive example`() {\n        lintMethod(\n            \"\"\"\n                    |class Example {\n                    |    val a = list.map { elem ->\n                    |        foo(elem)\n                    |    }\n                    |    val b = list.map { elem: Type ->\n                    |        foo(elem)\n                    |    }\n                    |    val c = list.map {\n                    |        bar(elem)\n                    |    }\n                    |    val d = list.map { elem -> bar(elem) }\n                    |    val e = list.map { elem: Type -> bar(elem) }\n                    |    val f = list.map { bar(elem) }\n                    |}\n            \"\"\".trimMargin()\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.WRONG_NEWLINES)\n    fun `in lambdas newline should be placed after an arrow`() {\n        lintMethod(\n            \"\"\"\n                    |class Example {\n                    |    val a = list.map {\n                    |        elem ->\n                    |            foo(elem)\n                    |    }\n                    |    val b = list.map { elem: Type\n                    |        ->\n                    |            foo(elem)\n                    |    }\n                    |    val c = list.map { elem\n                    |        -> bar(elem)\n                    |    }\n                    |    val d = list.map { elem: Type -> bar(elem)\n                    |        foo(elem)\n                    |    }\n                    |    val e = list.map { bar(elem)\n                    |        foo(elem)\n                    |    }\n                    |}\n            \"\"\".trimMargin(),\n            DiktatError(3, 14, ruleId, lambdaWithArrowWarn, true),\n            DiktatError(7, 9, ruleId, lambdaWithArrowWarn, true),\n            DiktatError(11, 9, ruleId, lambdaWithArrowWarn, true),\n            DiktatError(13, 35, ruleId, lambdaWithArrowWarn, true),\n            DiktatError(16, 22, ruleId, lambdaWithoutArrowWarn, true)\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.WRONG_NEWLINES)\n    fun `should warn if function consists of a single return statement - positive example`() {\n        lintMethod(\n            \"\"\"\n                    |fun foo() = \"lorem ipsum\"\n                    |\n                    |fun bar(): String {\n                    |    baz()\n                    |    return \"lorem ipsum\"\n                    |}\n                    |\n                    |fun qux(list: List<Int>): Int {\n                    |    list.filter {\n                    |        return@filter condition(it)\n                    |    }.forEach {\n                    |        return 0\n                    |    }\n                    |    return list.first()\n                    |}\n                    |\n                    |fun quux() { return }\n                    |\n                    |fun quux2(): Unit { return }\n            \"\"\".trimMargin()\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.WRONG_NEWLINES)\n    fun `should warn for array access expression`() {\n        lintMethod(\n            \"\"\"\n                    |fun bar(): String {\n                    |    val a = list.responseBody!![0].\n                    |    name\n                    |}\n            \"\"\".trimMargin(),\n            DiktatError(2, 35, ruleId, \"$shouldBreakBefore .\", true)\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.WRONG_NEWLINES)\n    fun `long argument list should be split into several lines - positive example`() {\n        lintMethod(\n            \"\"\"\n                    |class SmallExample(val a: Int)\n                    |\n                    |class Example(val a: Int,\n                    |              val b: Int) {\n                    |    fun foo(a: Int) { }\n                    |\n                    |    fun bar(\n                    |            a: Int,\n                    |            b: Int\n                    |    ) { }\n                    |}\n            \"\"\".trimMargin()\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.WRONG_NEWLINES)\n    @Disabled(\"Will be implemented later\")\n    fun `long argument list should be split into several lines`() {\n        lintMethod(\n            \"\"\"\n                    |class SmallExample(val a: Int)\n                    |\n                    |class Example(val a: Int, val b: Int) {\n                    |    fun foo(a: Int) { }\n                    |\n                    |    fun bar(\n                    |            a: Int, b: Int\n                    |    ) { }\n                    |}\n            \"\"\".trimMargin(),\n            DiktatError(3, 14, ruleId, \"${WRONG_NEWLINES.warnText()} argument list should be split into several lines\", true),\n            DiktatError(7, 12, ruleId, \"${WRONG_NEWLINES.warnText()} argument list should be split into several lines\", true)\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.WRONG_NEWLINES)\n    fun `should warn if function consists of a single return statement`() {\n        lintMethod(\n            \"\"\"\n                    |fun foo(): String {\n                    |    return \"lorem ipsum\"\n                    |}\n            \"\"\".trimMargin(),\n            DiktatError(2, 5, ruleId, singleReturnWarn, true)\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.WRONG_NEWLINES)\n    fun `shouldn't warn if function consists of a single return statement with a nested return`() {\n        lintMethod(\n            \"\"\"\n                    |fun foo(): String {\n                    |    return Demo(string ?: return null)\n                    |}\n            \"\"\".trimMargin(),\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.WRONG_NEWLINES)\n    @Suppress(\"TOO_LONG_FUNCTION\")\n    fun `should not trigger`() {\n        lintMethod(\n            \"\"\"\n                    |fun foo(): String {\n                    |\n                    |       val a = java.lang.Boolean.getBoolean(properties.getProperty(\"parallel.mode\"))\n                    |\n                    |        allProperties?.filter {\n                    |           predicate(it)\n                    |           val x = listOf(1,2,3).filter { it < 3 }\n                    |           x == 0\n                    |        }\n                    |        .foo()\n                    |        .bar()\n                    |\n                    |        allProperties?.filter {\n                    |           predicate(it)\n                    |        }\n                    |        .foo()\n                    |        .bar()\n                    |        .let {\n                    |           it.some()\n                    |        }\n                    |\n                    |        allProperties\n                    |        ?.filter {\n                    |           predicate(it)\n                    |        }\n                    |        .foo()\n                    |        .bar()\n                    |        .let {\n                    |           mutableListOf().also {\n                    |\n                    |           }\n                    |        }\n                    |}\n            \"\"\".trimMargin()\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.WRONG_NEWLINES)\n    fun `should trigger for several lambdas on same line`() {\n        lintMethod(\n            \"\"\"\n                    |fun foo(): String {\n                    |        allProperties.filter { predicate(it) }\n                    |        .foo()\n                    |        .bar()\n                    |\n                    |        allProperties?.filter { predicate(it) }\n                    |        .foo()\n                    |        .bar()\n                    |\n                    |        list.foo()\n                    |           .bar()\n                    |           .filter {\n                    |               baz()\n                    |           }\n                    |\n                    |        list.filter {\n                    |\n                    |        }\n                    |        .map(::foo).filter {\n                    |           bar()\n                    |         }\n                    |}\n            \"\"\".trimMargin(),\n            DiktatError(16, 9, ruleId, dotQuaOrSafeAccessOrPostfixExpression, true),\n            DiktatError(19, 20, ruleId, \"$functionalStyleWarn .\", true),\n            rulesConfigList = rulesConfigListShort\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.WRONG_NEWLINES)\n    fun `should suggest newlines in a long argument list of a constructor`() {\n        lintMethod(\n            \"\"\"\n                |class Foo(val arg1: Int, arg2: Int) { }\n                |\n                |class Foo(val arg1: Int, arg2: Int, arg3: Int) {\n                |    constructor(arg1: Int, arg2: String, arg3: String) : this(arg1, 0, 0) { }\n                |}\n                |\n                |class Foo(val arg1: Int,\n                |          var arg2: Int,\n                |          arg3: Int\n                |) { }\n            \"\"\".trimMargin(),\n            DiktatError(3, 10, ruleId, \"${WRONG_NEWLINES.warnText()} first parameter should be placed on a separate line or all other parameters \" +\n                    \"should be aligned with it in declaration of <Foo>\", true),\n            DiktatError(3, 10, ruleId, \"${WRONG_NEWLINES.warnText()} value parameters should be placed on different lines in declaration of <Foo>\", true),\n            DiktatError(4, 16, ruleId, \"${WRONG_NEWLINES.warnText()} first parameter should be placed on a separate line or all other parameters \" +\n                    \"should be aligned with it in declaration of <Foo>\", true),\n            DiktatError(4, 16, ruleId, \"${WRONG_NEWLINES.warnText()} value parameters should be placed on different lines in declaration of <Foo>\", true),\n            DiktatError(4, 62, ruleId, \"${WRONG_NEWLINES.warnText()} first value argument (arg1) should be placed on the new line or \" +\n                    \"all other parameters should be aligned with it\", true),\n            DiktatError(4, 62, ruleId, \"${WRONG_NEWLINES.warnText()} value arguments should be placed on different lines\", true)\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.WRONG_NEWLINES)\n    fun `should suggest newlines in a long argument list`() {\n        lintMethod(\n            \"\"\"\n                |fun foo(arg1: Int, arg2: Int) { }\n                |\n                |fun bar(arg1: Int, arg2: Int, arg3: Int) { }\n                |\n                |// should not trigger on functional types\n                |fun bar(arg1: (_arg1: Int, _arg2: Int, _arg3: Int) -> Int) { }\n                |\n                |// should not trigger on functional type receivers\n                |fun bar(arg1: Foo.(_arg1: Int, _arg2: Int, _arg3: Int) -> Int) { }\n                |\n                |fun baz(arg1: Int,\n                |        arg2: Int,\n                |        arg3: Int\n                |) { }\n            \"\"\".trimMargin(),\n            DiktatError(3, 8, ruleId, \"${WRONG_NEWLINES.warnText()} first parameter should be placed on a separate line or all other parameters \" +\n                    \"should be aligned with it in declaration of <bar>\", true),\n            DiktatError(3, 8, ruleId, \"${WRONG_NEWLINES.warnText()} value parameters should be placed on different lines in declaration of <bar>\", true)\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.WRONG_NEWLINES)\n    fun `should not raise warning on value arguments`() {\n        lintMethod(\n            \"\"\"\n                |class SomeRule(configRules: List<Int>) : Rule(\"id\",\n                |configRules,\n                |listOf(\"foo\", \"baz\")\n                |) {\n                |\n                |}\n            \"\"\".trimMargin()\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.WRONG_NEWLINES)\n    fun `should not raise warning on list params`() {\n        lintMethod(\n            \"\"\"\n                |class SomeRule(configRules: List<Int>) : Rule(\"id\",\n                |configRules,\n                |listOf(\"foo\", \"baz\", \"triple\", \"bar\")\n                |) {\n                |\n                |}\n            \"\"\".trimMargin()\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.WRONG_NEWLINES)\n    fun `should raise warning on value arguments`() {\n        lintMethod(\n            \"\"\"\n                |class SomeRule(configRules: List<Int>) : Rule(\"id\", configRules, listOf(\"foo\", \"baz\")) {\n                |\n                |}\n            \"\"\".trimMargin(),\n            DiktatError(1, 46, ruleId, \"${WRONG_NEWLINES.warnText()} first value argument (\\\"id\\\") should be placed on the new line or \" +\n                    \"all other parameters should be aligned with it\", true),\n            DiktatError(1, 46, ruleId, \"${WRONG_NEWLINES.warnText()} value arguments should be placed on different lines\", true),\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.WRONG_NEWLINES)\n    fun `should suggest newlines in a long supertype list`() {\n        lintMethod(\n            \"\"\"\n                |class Foo :\n                |    FooBase<Bar>(),\n                |    BazInterface,\n                |    BazSuperclass { }\n                |\n                |class Foo : FooBase<Bar>(), BazInterface,\n                |    BazSuperclass { }\n                |\n                |class Foo : FooBase<Bar>(), BazInterface, BazSuperclass { }\n                |\n                |class Foo : FooBase<Bar>() { }\n            \"\"\".trimMargin(),\n            DiktatError(6, 13, ruleId, \"${WRONG_NEWLINES.warnText()} supertype list entries should be placed on different lines in declaration of <Foo>\", true),\n            DiktatError(9, 13, ruleId, \"${WRONG_NEWLINES.warnText()} supertype list entries should be placed on different lines in declaration of <Foo>\", true)\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.WRONG_NEWLINES)\n    fun `should warn dot qualified with first on same line`() {\n        lintMethod(\n            \"\"\"\n                |fun foo() {\n                |   x.map()\n                |   .gre().few().dfh().qwe()\n                |}\n                |\n                |fun foo() {\n                |   x.map()\n                |   .gre()\n                |   .few()\n                |}\n                |\n                |fun foo() {\n                |   x.map().gre().few().qwe()\n                |}\n            \"\"\".trimMargin(),\n            DiktatError(2, 4, ruleId, dotQuaOrSafeAccessOrPostfixExpression, true),\n            DiktatError(3, 22, ruleId, \"$functionalStyleWarn .\", true),\n            DiktatError(13, 4, ruleId, dotQuaOrSafeAccessOrPostfixExpression, true),\n            DiktatError(13, 23, ruleId, \"$functionalStyleWarn .\", true)\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.WRONG_NEWLINES)\n    fun `should warn dot qualified with first on diff line`() {\n        lintMethod(\n            \"\"\"\n                |fun foo() {\n                |   x\n                |   .map()\n                |   .gre().few().qwe().qwe()\n                |}\n                |\n                |fun foo() {\n                |   x\n                |   .map().gre().few().vfd()\n                |}\n                |\n                |fun foo() {\n                |   x\n                |   .map()\n                |   .gre()\n                |   .few()\n                |}\n            \"\"\".trimMargin(),\n            DiktatError(2, 4, ruleId, dotQuaOrSafeAccessOrPostfixExpression, true),\n            DiktatError(4, 22, ruleId, \"$functionalStyleWarn .\", true),\n            DiktatError(8, 4, ruleId, dotQuaOrSafeAccessOrPostfixExpression, true),\n            DiktatError(9, 22, ruleId, \"$functionalStyleWarn .\", true)\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.WRONG_NEWLINES)\n    fun `should warn dot qualified with safe access`() {\n        lintMethod(\n            \"\"\"\n                |fun foo() {\n                |   x\n                |   ?.map()\n                |   .gre().few()\n                |}\n                |\n                |fun foo() {\n                |   x\n                |   ?.map().gre().few()\n                |}\n                |fun foo() {\n                |   x\n                |   ?.map()\n                |   .gre()\n                |   .few()\n                |}\n                |\n                |fun foo() {\n                |   x?.map()\n                |   .gre()\n                |   .few()\n                |}\n            \"\"\".trimMargin(),\n            DiktatError(2, 4, ruleId, dotQuaOrSafeAccessOrPostfixExpression, true),\n            DiktatError(4, 10, ruleId, \"$functionalStyleWarn .\", true),\n            DiktatError(8, 4, ruleId, dotQuaOrSafeAccessOrPostfixExpression, true),\n            DiktatError(9, 11, ruleId, \"$functionalStyleWarn .\", true),\n            DiktatError(9, 17, ruleId, \"$functionalStyleWarn .\", true),\n            rulesConfigList = rulesConfigListShort\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.WRONG_NEWLINES)\n    fun `should warn dot qualified with exclexcl`() {\n        lintMethod(\n            \"\"\"\n                |fun foo() {\n                |   x!!.map()\n                |   .gre()\n                |   .few()\n                |}\n                |\n                |fun foo() {\n                |   x!!\n                |   .map()\n                |   .gre()\n                |   .few()\n                |}\n                |\n                |fun foo() {\n                |   x!!\n                |   .map().gre()\n                |   .few()\n                |}\n                |\n                |fun foo() {\n                |   x!!.map()\n                |   .gre().few()\n                |}\n            \"\"\".trimMargin(),\n            DiktatError(2, 7, ruleId, \"$functionalStyleWarn .\", true),\n            DiktatError(15, 4, ruleId, dotQuaOrSafeAccessOrPostfixExpression, true),\n            DiktatError(16, 10, ruleId, \"$functionalStyleWarn .\", true),\n            DiktatError(21, 4, ruleId, dotQuaOrSafeAccessOrPostfixExpression, true),\n            DiktatError(21, 7, ruleId, \"$functionalStyleWarn .\", true),\n            DiktatError(22, 10, ruleId, \"$functionalStyleWarn .\", true),\n            rulesConfigList = rulesConfigListShort\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.WRONG_NEWLINES)\n    fun `should warn elvis`() {\n        lintMethod(\n            \"\"\"\n                |fun foo() {\n                |\n                |   z.goo()\n                |       ?:\n                |        goo()\n                |\n                |   x.goo()\n                |       ?:goo()\n                |\n                |   y.ds()?:gh()\n                |}\n            \"\"\".trimMargin(),\n            DiktatError(4, 8, ruleId, \"$shouldBreakBefore ?:\", true)\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.WRONG_NEWLINES)\n    fun `should warn elvis with several dot qualifided`() {\n        lintMethod(\n            \"\"\"\n                |fun foo() {\n                |   z.goo()\n                |       ?:\n                |        goo().gor().goo()\n                |}\n            \"\"\".trimMargin(),\n            DiktatError(3, 8, ruleId, \"$shouldBreakBefore ?:\", true)\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.WRONG_NEWLINES)\n    fun `test configuration for calls in one line`() {\n        lintMethod(\n            \"\"\"\n                |fun foo() {\n                |   z.goo().foo().qwe()\n                |   z!!.htr().foo()\n                |   x.goo().foo().goo()\n                |   x.gf().gfh() ?: true\n                |   x.gf().fge().qwe().fd()\n                |}\n            \"\"\".trimMargin(),\n            DiktatError(6, 4, ruleId, dotQuaOrSafeAccessOrPostfixExpression, true),\n            DiktatError(6, 22, ruleId, \"$functionalStyleWarn .\", true), rulesConfigList = rulesConfigList\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.WRONG_NEWLINES)\n    fun `more test for prefix`() {\n        lintMethod(\n            \"\"\"\n                |fun foo() {\n                |   foo\n                |       .bar()\n                |       .goo()\n                |       .qwe()!!\n                |\n                |   goo()!!.gre()\n                |\n                |   bfr()!!.qwe().foo().qwe().dg()\n                |}\n                |\n                |fun foo() {\n                |   foo\n                |       .bar()\n                |       .goo()!!\n                |       .qwe()\n                |}\n            \"\"\".trimMargin(),\n            DiktatError(9, 4, ruleId, dotQuaOrSafeAccessOrPostfixExpression, true),\n            DiktatError(9, 29, ruleId, \"$functionalStyleWarn .\", true)\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.WRONG_NEWLINES)\n    fun `more test for unsafe calls`() {\n        lintMethod(\n            \"\"\"\n                |fun foo() {\n                |   foo\n                |       .bar()\n                |       .goo()!!\n                |       .qwe()\n                |\n                |   val x = foo\n                |       .bar!!\n                |       .baz\n                |}\n            \"\"\".trimMargin()\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.WRONG_NEWLINES)\n    fun `test for null safety one line`() {\n        lintMethod(\n            \"\"\"\n                |fun foo() {\n                |   foo.qwe() ?: bar.baz()\n                |   foo ?: bar().qwe()\n                |   foo ?: bar().qwe().qwe()\n                |}\n            \"\"\".trimMargin(),\n            DiktatError(2, 14, ruleId, \"$functionalStyleWarn ?:\", true),\n            DiktatError(4, 8, ruleId, \"$functionalStyleWarn ?:\", true),\n            DiktatError(4, 11, ruleId, dotQuaOrSafeAccessOrPostfixExpression, true),\n            DiktatError(4, 22, ruleId, \"$functionalStyleWarn .\", true),\n            rulesConfigList = rulesConfigListShort\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.WRONG_NEWLINES)\n    fun `test for not first prefix`() {\n        lintMethod(\n            \"\"\"\n                |fun foo() {\n                |   a().b!!.c()\n                |   a().b.c()!!\n                |}\n            \"\"\".trimMargin(),\n            DiktatError(2, 4, ruleId, dotQuaOrSafeAccessOrPostfixExpression, true),\n            DiktatError(2, 11, ruleId, \"$functionalStyleWarn .\", true),\n            DiktatError(3, 4, ruleId, dotQuaOrSafeAccessOrPostfixExpression, true),\n            DiktatError(3, 9, ruleId, \"$functionalStyleWarn .\", true),\n            rulesConfigList = rulesConfigListShort\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.WRONG_NEWLINES)\n    fun `test for null safety several lines`() {\n        lintMethod(\n            \"\"\"\n                |fun foo() {\n                |   foo.qwe()\n                |       ?: bar.baz()\n                |   foo\n                |       ?: bar().qwe()\n                |   foo\n                |       ?: bar().qwe().qwe()\n                |   foo\n                |       .qwe() ?: qwe().qwe()\n                |   foo().qwe() ?: qwe().\n                |                           qwe()\n                |   foo().qwe() ?: qwe()\n                |                       .qwe()\n                |}\n            \"\"\".trimMargin(),\n            DiktatError(7, 11, ruleId, dotQuaOrSafeAccessOrPostfixExpression, true),\n            DiktatError(7, 22, ruleId, \"$functionalStyleWarn .\", true),\n            DiktatError(9, 15, ruleId, \"$functionalStyleWarn ?:\", true),\n            DiktatError(10, 16, ruleId, \"$functionalStyleWarn ?:\", true),\n            DiktatError(10, 24, ruleId, \"$shouldBreakBefore .\", true),\n            DiktatError(12, 16, ruleId, \"$functionalStyleWarn ?:\", true),\n            rulesConfigList = rulesConfigListShort\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.WRONG_NEWLINES)\n    fun `test for null safety correct examples`() {\n        lintMethod(\n            \"\"\"\n                |fun foo() {\n                |   foo\n                |       ?: bar\n                |           .bar()\n                |           .qux()\n                |\n                |\n                |   foo.bar()\n                |       .baz()\n                |       .qux()\n                |       ?: boo\n                |}\n            \"\"\".trimMargin(),\n            rulesConfigList = rulesConfigListShort\n        )\n    }\n\n    @Test\n    @Tags(Tag(WarningNames.WRONG_NEWLINES), Tag(WarningNames.COMPLEX_EXPRESSION))\n    fun `complex expression in condition`() {\n        lintMethod(\n            \"\"\"\n                |fun foo() {\n                |   if(a.b.c) {}\n                |   while(a?.b?.c) {}\n                |   when(a.b!!.c) {}\n                |   goo(a?.b.c)\n                |}\n            \"\"\".trimMargin(),\n            DiktatError(2, 10, ruleId, \"${COMPLEX_EXPRESSION.warnText()} .\", false),\n            DiktatError(3, 14, ruleId, \"${COMPLEX_EXPRESSION.warnText()} ?.\", false),\n            DiktatError(4, 14, ruleId, \"${COMPLEX_EXPRESSION.warnText()} .\", false),\n            DiktatError(5, 12, ruleId, \"${COMPLEX_EXPRESSION.warnText()} .\", false),\n            rulesConfigList = rulesConfigListShort\n        )\n    }\n\n    @Test\n    @Tags(Tag(WarningNames.WRONG_NEWLINES), Tag(WarningNames.COMPLEX_EXPRESSION))\n    fun `complex expression in condition with double warnings`() {\n        lintMethod(\n            \"\"\"\n                |fun foo() {\n                |   if(a().b().c()) {}\n                |}\n            \"\"\".trimMargin(),\n            DiktatError(2, 7, ruleId, dotQuaOrSafeAccessOrPostfixExpression, true),\n            DiktatError(2, 14, ruleId, \"${COMPLEX_EXPRESSION.warnText()} .\", false),\n            DiktatError(2, 14, ruleId, \"$functionalStyleWarn .\", true),\n            rulesConfigList = rulesConfigListShort\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.WRONG_NEWLINES)\n    fun `shouldn't fall with NPE`() {\n        lintMethod(\n            \"\"\"\n                |val TEST_FUNC = { _: Int, _: Set<Int>, _: Int, ->\n                |}\n            \"\"\".trimMargin(),\n            DiktatError(1, 19, ruleId, \"${WRONG_NEWLINES.warnText()} \" +\n                    \"first parameter should be placed on a separate line or all other parameters should be aligned with it in declaration of <null>\", true),\n            DiktatError(1, 19, ruleId, \"${WRONG_NEWLINES.warnText()} value parameters should be placed on different lines\", true),\n            )\n    }\n\n    @Test\n    @Tag(WarningNames.WRONG_NEWLINES)\n    fun `not complaining on fun without return type`() {\n        lintMethod(\n            \"\"\"\n                |fun foo(x: Int, y: Int) = x + y\n            \"\"\".trimMargin(),\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.COMPLEX_EXPRESSION)\n    fun `COMPLEX_EXPRESSION shouldn't trigger for declarations in kts`(@TempDir tempDir: Path) {\n        lintMethodWithFile(\n            \"\"\"\n                |dependencies {\n                |    implementation(libs.spring.cloud.starter.gateway)\n                |}\n            \"\"\".trimMargin(),\n            tempDir = tempDir,\n            fileName = \"build.gradle.kts\"\n        )\n    }\n\n    @Test\n    @Tags(Tag(WarningNames.WRONG_NEWLINES), Tag(WarningNames.COMPLEX_EXPRESSION))\n    fun `shouldn't trigger on allowed many calls in one line`() {\n        lintMethod(\n            \"\"\"\n                |fun foo() {\n                |   if(a().b().c().d().e()) {}\n                |}\n            \"\"\".trimMargin(),\n            rulesConfigList = rulesConfigListLong\n        )\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/test/kotlin/com/saveourtool/diktat/ruleset/chapter3/files/SemicolonsRuleFixTest.kt",
    "content": "package com.saveourtool.diktat.ruleset.chapter3.files\n\nimport com.saveourtool.diktat.ruleset.rules.chapter3.files.SemicolonsRule\nimport com.saveourtool.diktat.util.FixTestBase\nimport generated.WarningNames\nimport org.junit.jupiter.api.Tag\nimport org.junit.jupiter.api.Test\n\nclass SemicolonsRuleFixTest : FixTestBase(\"test/paragraph3/semicolons\", ::SemicolonsRule) {\n    @Test\n    @Tag(WarningNames.REDUNDANT_SEMICOLON)\n    fun `should remove redundant semicolons`() {\n        fixAndCompare(\"SemicolonsExpected.kt\", \"SemicolonsTest.kt\")\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/test/kotlin/com/saveourtool/diktat/ruleset/chapter3/files/SemicolonsRuleWarnTest.kt",
    "content": "package com.saveourtool.diktat.ruleset.chapter3.files\n\nimport com.saveourtool.diktat.api.DiktatError\nimport com.saveourtool.diktat.common.config.rules.DIKTAT_RULE_SET_ID\nimport com.saveourtool.diktat.ruleset.constants.Warnings.REDUNDANT_SEMICOLON\nimport com.saveourtool.diktat.ruleset.rules.chapter3.files.SemicolonsRule\nimport com.saveourtool.diktat.util.LintTestBase\nimport generated.WarningNames\nimport org.junit.jupiter.api.Tag\nimport org.junit.jupiter.api.Test\n\nclass SemicolonsRuleWarnTest : LintTestBase(::SemicolonsRule) {\n    private val ruleId = \"$DIKTAT_RULE_SET_ID:${SemicolonsRule.NAME_ID}\"\n\n    @Test\n    @Tag(WarningNames.REDUNDANT_SEMICOLON)\n    fun `should forbid EOL semicolons`() {\n        lintMethod(\n            \"\"\"\n                    |enum class Example {\n                    |    A,\n                    |    B\n                    |    ;\n                    |\n                    |    fun foo() {};\n                    |    val a = 0;\n                    |    val b = if (condition) { bar(); baz()} else qux\n                    |};\n            \"\"\".trimMargin(),\n            DiktatError(6, 17, ruleId, \"${REDUNDANT_SEMICOLON.warnText()} fun foo() {};\", true),\n            DiktatError(7, 14, ruleId, \"${REDUNDANT_SEMICOLON.warnText()} val a = 0;\", true),\n            DiktatError(9, 2, ruleId, \"${REDUNDANT_SEMICOLON.warnText()} };\", true)\n        )\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/test/kotlin/com/saveourtool/diktat/ruleset/chapter3/files/TopLevelOrderRuleFixTest.kt",
    "content": "package com.saveourtool.diktat.ruleset.chapter3.files\n\nimport com.saveourtool.diktat.ruleset.rules.chapter3.files.TopLevelOrderRule\nimport com.saveourtool.diktat.util.FixTestBase\n\nimport generated.WarningNames\nimport org.junit.jupiter.api.Tag\nimport org.junit.jupiter.api.Test\n\nclass TopLevelOrderRuleFixTest : FixTestBase(\"test/paragraph3/top_level\", ::TopLevelOrderRule) {\n    @Test\n    @Tag(WarningNames.TOP_LEVEL_ORDER)\n    fun `should fix top level order`() {\n        fixAndCompare(\"TopLevelSortExpected.kt\", \"TopLevelSortTest.kt\")\n    }\n\n    @Test\n    @Tag(WarningNames.TOP_LEVEL_ORDER)\n    fun `should fix top level order with comment`() {\n        fixAndCompare(\"TopLevelWithCommentExpected.kt\", \"TopLevelWithCommentTest.kt\")\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/test/kotlin/com/saveourtool/diktat/ruleset/chapter3/files/TopLevelOrderRuleWarnTest.kt",
    "content": "package com.saveourtool.diktat.ruleset.chapter3.files\n\nimport com.saveourtool.diktat.common.config.rules.DIKTAT_RULE_SET_ID\nimport com.saveourtool.diktat.ruleset.constants.Warnings.TOP_LEVEL_ORDER\nimport com.saveourtool.diktat.ruleset.rules.chapter3.files.TopLevelOrderRule\nimport com.saveourtool.diktat.util.LintTestBase\n\nimport com.saveourtool.diktat.api.DiktatError\nimport generated.WarningNames\nimport org.junit.jupiter.api.Tag\nimport org.junit.jupiter.api.Test\n\nclass TopLevelOrderRuleWarnTest : LintTestBase(::TopLevelOrderRule) {\n    private val ruleId = \"$DIKTAT_RULE_SET_ID:${TopLevelOrderRule.NAME_ID}\"\n\n    @Test\n    @Tag(WarningNames.TOP_LEVEL_ORDER)\n    fun `correct order`() {\n        lintMethod(\n            \"\"\"\n                |const val CONSTANT = 42\n                |val topLevelProperty = \"String constant\"\n                |lateinit var q: String\n                |fun String.foo() {}\n                |fun foo() {}\n                |private fun gio() {}\n            \"\"\".trimMargin()\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.TOP_LEVEL_ORDER)\n    fun `wrong order`() {\n        lintMethod(\n            \"\"\"\n                |class A {}\n                |lateinit var q: String\n                |interface B {}\n                |fun foo() {}\n                |fun String.foo() {}\n                |private val et = 0\n                |public const val g = 9.8\n                |object B {}\n            \"\"\".trimMargin(),\n            DiktatError(1, 1, ruleId, \"${TOP_LEVEL_ORDER.warnText()} class A {}\", true),\n            DiktatError(2, 1, ruleId, \"${TOP_LEVEL_ORDER.warnText()} lateinit var q: String\", true),\n            DiktatError(3, 1, ruleId, \"${TOP_LEVEL_ORDER.warnText()} interface B {}\", true),\n            DiktatError(4, 1, ruleId, \"${TOP_LEVEL_ORDER.warnText()} fun foo() {}\", true),\n            DiktatError(5, 1, ruleId, \"${TOP_LEVEL_ORDER.warnText()} fun String.foo() {}\", true),\n            DiktatError(6, 1, ruleId, \"${TOP_LEVEL_ORDER.warnText()} private val et = 0\", true),\n            DiktatError(7, 1, ruleId, \"${TOP_LEVEL_ORDER.warnText()} public const val g = 9.8\", true),\n            DiktatError(8, 1, ruleId, \"${TOP_LEVEL_ORDER.warnText()} object B {}\", true)\n        )\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/test/kotlin/com/saveourtool/diktat/ruleset/chapter3/spaces/ExpectedIndentationError.kt",
    "content": "package com.saveourtool.diktat.ruleset.chapter3.spaces\n\nimport com.saveourtool.diktat.common.config.rules.DIKTAT_RULE_SET_ID\nimport com.saveourtool.diktat.ruleset.constants.Warnings.WRONG_INDENTATION\nimport com.saveourtool.diktat.ruleset.junit.ExpectedLintError\nimport com.saveourtool.diktat.ruleset.rules.chapter3.files.IndentationRule.Companion.NAME_ID\nimport com.saveourtool.diktat.api.DiktatError\n\n/**\n * The expected indentation error (extracted from annotated code fragments).\n *\n * @property line the line number (1-based).\n * @property column the column number (1-based).\n */\nclass ExpectedIndentationError(override val line: Int,\n                               override val column: Int = 1,\n                               private val message: String\n) : ExpectedLintError {\n    /**\n     * @param line the line number (1-based).\n     * @param column the column number (1-based).\n     * @param expectedIndent the expected indentation level (in space characters).\n     * @param actualIndent the actual indentation level (in space characters).\n     */\n    constructor(line: Int,\n                column: Int = 1,\n                expectedIndent: Int,\n                actualIndent: Int\n    ) : this(\n        line,\n        column,\n        warnText(expectedIndent)(actualIndent)\n    )\n\n    override fun asLintError(): DiktatError =\n        DiktatError(\n            line,\n            column,\n            \"$DIKTAT_RULE_SET_ID:$NAME_ID\",\n            message,\n            true)\n\n    private companion object {\n        private val warnText: (Int) -> (Int) -> String = { expectedIndent ->\n            { actualIndent ->\n                \"${WRONG_INDENTATION.warnText()} expected $expectedIndent but was $actualIndent\"\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/test/kotlin/com/saveourtool/diktat/ruleset/chapter3/spaces/IndentationConfigAwareTest.kt",
    "content": "@file:Suppress(\"FILE_UNORDERED_IMPORTS\")// False positives, see #1494.\n\npackage com.saveourtool.diktat.ruleset.chapter3.spaces\n\nimport com.saveourtool.diktat.ruleset.junit.NaturalDisplayName\nimport com.saveourtool.diktat.ruleset.rules.chapter3.files.IndentationAmount.EXTENDED\nimport com.saveourtool.diktat.ruleset.rules.chapter3.files.IndentationAmount.NONE\nimport com.saveourtool.diktat.ruleset.rules.chapter3.files.IndentationAmount.SINGLE\nimport com.saveourtool.diktat.ruleset.rules.chapter3.files.IndentationConfigAware.Factory.withIndentationConfig\nimport com.saveourtool.diktat.ruleset.utils.indentation.IndentationConfig.Companion.INDENTATION_SIZE\n\nimport org.assertj.core.api.Assertions.assertThat\nimport org.junit.jupiter.api.TestMethodOrder\nimport org.junit.jupiter.params.ParameterizedTest\nimport org.junit.jupiter.params.provider.ValueSource\n\nimport com.saveourtool.diktat.ruleset.chapter3.spaces.IndentationConfigFactory as IndentationConfig\n\n@TestMethodOrder(NaturalDisplayName::class)\nclass IndentationConfigAwareTest {\n    @ParameterizedTest(name = \"$INDENTATION_SIZE = {0}\")\n    @ValueSource(ints = [2, 4, 8])\n    fun `Int + IndentationAmount`(indentationSize: Int) {\n        val config = IndentationConfig(INDENTATION_SIZE to indentationSize)\n\n        withIndentationConfig(config) {\n            assertThat(42 + NONE).isEqualTo(42)\n            assertThat(42 + SINGLE).isEqualTo(42 + indentationSize)\n            assertThat(42 + EXTENDED).isEqualTo(42 + 2 * indentationSize)\n        }\n    }\n\n    @ParameterizedTest(name = \"$INDENTATION_SIZE = {0}\")\n    @ValueSource(ints = [2, 4, 8])\n    fun `Int - IndentationAmount`(indentationSize: Int) {\n        val config = IndentationConfig(INDENTATION_SIZE to indentationSize)\n\n        withIndentationConfig(config) {\n            assertThat(42 - NONE).isEqualTo(42)\n            assertThat(42 - SINGLE).isEqualTo(42 - indentationSize)\n            assertThat(42 - EXTENDED).isEqualTo(42 - 2 * indentationSize)\n        }\n    }\n\n    @ParameterizedTest(name = \"$INDENTATION_SIZE = {0}\")\n    @ValueSource(ints = [2, 4, 8])\n    fun `IndentationAmount + Int`(indentationSize: Int) {\n        val config = IndentationConfig(INDENTATION_SIZE to indentationSize)\n\n        withIndentationConfig(config) {\n            assertThat(NONE + 42).isEqualTo(42 + NONE)\n            assertThat(SINGLE + 42).isEqualTo(42 + SINGLE)\n            assertThat(EXTENDED + 42).isEqualTo(42 + EXTENDED)\n\n            assertThat(42 + (SINGLE + 2)).isEqualTo((42 + SINGLE) + 2)\n        }\n    }\n\n    @ParameterizedTest(name = \"$INDENTATION_SIZE = {0}\")\n    @ValueSource(ints = [2, 4, 8])\n    fun `IndentationAmount - Int`(indentationSize: Int) {\n        val config = IndentationConfig(INDENTATION_SIZE to indentationSize)\n\n        withIndentationConfig(config) {\n            assertThat(NONE - 42).isEqualTo(-(42 - NONE))\n            assertThat(SINGLE - 42).isEqualTo(-(42 - SINGLE))\n            assertThat(EXTENDED - 42).isEqualTo(-(42 - EXTENDED))\n\n            assertThat(42 - (SINGLE - 2)).isEqualTo(42 - SINGLE + 2)\n        }\n    }\n\n    @ParameterizedTest(name = \"$INDENTATION_SIZE = {0}\")\n    @ValueSource(ints = [2, 4, 8])\n    fun `IndentationAmount + IndentationAmount`(indentationSize: Int) {\n        val config = IndentationConfig(INDENTATION_SIZE to indentationSize)\n\n        withIndentationConfig(config) {\n            assertThat(NONE + SINGLE).isEqualTo(0 + SINGLE)\n            assertThat(SINGLE + SINGLE).isEqualTo(0 + EXTENDED)\n\n            assertThat(42 + SINGLE + SINGLE).isEqualTo(42 + EXTENDED)\n            assertThat(42 + (SINGLE + SINGLE)).isEqualTo(42 + EXTENDED)\n        }\n    }\n\n    @ParameterizedTest(name = \"$INDENTATION_SIZE = {0}\")\n    @ValueSource(ints = [2, 4, 8])\n    fun `IndentationAmount - IndentationAmount`(indentationSize: Int) {\n        val config = IndentationConfig(INDENTATION_SIZE to indentationSize)\n\n        withIndentationConfig(config) {\n            assertThat(NONE - SINGLE).isEqualTo(0 - SINGLE)\n            assertThat(SINGLE - SINGLE).isEqualTo(0)\n            assertThat(EXTENDED - SINGLE).isEqualTo(0 + SINGLE)\n            assertThat(NONE - EXTENDED).isEqualTo(0 - EXTENDED)\n\n            assertThat(42 + (SINGLE - SINGLE)).isEqualTo(42 + SINGLE - SINGLE)\n        }\n    }\n\n    @ParameterizedTest(name = \"$INDENTATION_SIZE = {0}\")\n    @ValueSource(ints = [2, 4, 8])\n    fun unaryPlus(indentationSize: Int) {\n        val config = IndentationConfig(INDENTATION_SIZE to indentationSize)\n\n        withIndentationConfig(config) {\n            assertThat(+NONE).isEqualTo(0)\n            assertThat(+SINGLE).isEqualTo(indentationSize)\n            assertThat(+EXTENDED).isEqualTo(2 * indentationSize)\n\n            assertThat(EXTENDED - SINGLE).isEqualTo(+SINGLE)\n        }\n    }\n\n    @ParameterizedTest(name = \"$INDENTATION_SIZE = {0}\")\n    @ValueSource(ints = [2, 4, 8])\n    fun unaryMinus(indentationSize: Int) {\n        val config = IndentationConfig(INDENTATION_SIZE to indentationSize)\n\n        withIndentationConfig(config) {\n            assertThat(-NONE).isEqualTo(0)\n            assertThat(-SINGLE).isEqualTo(-indentationSize)\n            assertThat(-EXTENDED).isEqualTo(-2 * indentationSize)\n\n            assertThat(NONE - SINGLE).isEqualTo(-SINGLE)\n            assertThat(NONE - EXTENDED).isEqualTo(-EXTENDED)\n        }\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/test/kotlin/com/saveourtool/diktat/ruleset/chapter3/spaces/IndentationConfigFactory.kt",
    "content": "package com.saveourtool.diktat.ruleset.chapter3.spaces\n\nimport com.saveourtool.diktat.ruleset.utils.indentation.IndentationConfig\n\ninternal object IndentationConfigFactory {\n    /**\n     * Creates an `IndentationConfig` from zero or more\n     * [config entries][configEntries]. Invoke without arguments to create a\n     * default `IndentationConfig`.\n     *\n     * @param configEntries the configuration entries to create this instance from.\n     * @return the configuration created.\n     * @see [IndentationConfig]\n     */\n    operator fun invoke(vararg configEntries: Pair<String, Any>): IndentationConfig =\n        IndentationConfig(mapOf(*configEntries).mapValues { (_, value) ->\n            value.toString()\n        })\n}\n"
  },
  {
    "path": "diktat-rules/src/test/kotlin/com/saveourtool/diktat/ruleset/chapter3/spaces/IndentationRuleFixTest.kt",
    "content": "@file:Suppress(\"FILE_UNORDERED_IMPORTS\")// False positives, see #1494.\n\npackage com.saveourtool.diktat.ruleset.chapter3.spaces\n\nimport com.saveourtool.diktat.common.config.rules.RulesConfig\nimport com.saveourtool.diktat.ruleset.constants.Warnings.WRONG_INDENTATION\nimport com.saveourtool.diktat.ruleset.junit.NaturalDisplayName\nimport com.saveourtool.diktat.ruleset.rules.chapter3.files.IndentationRule\nimport com.saveourtool.diktat.ruleset.utils.indentation.IndentationConfig.Companion.ALIGNED_PARAMETERS\nimport com.saveourtool.diktat.ruleset.utils.indentation.IndentationConfig.Companion.EXTENDED_INDENT_AFTER_OPERATORS\nimport com.saveourtool.diktat.ruleset.utils.indentation.IndentationConfig.Companion.EXTENDED_INDENT_BEFORE_DOT\nimport com.saveourtool.diktat.ruleset.utils.indentation.IndentationConfig.Companion.EXTENDED_INDENT_FOR_EXPRESSION_BODIES\nimport com.saveourtool.diktat.ruleset.utils.indentation.IndentationConfig.Companion.EXTENDED_INDENT_OF_PARAMETERS\nimport com.saveourtool.diktat.ruleset.utils.indentation.IndentationConfig.Companion.NEWLINE_AT_END\nimport com.saveourtool.diktat.test.framework.processing.TestFileContent\nimport com.saveourtool.diktat.util.FixTestBase\n\nimport generated.WarningNames\nimport org.intellij.lang.annotations.Language\nimport org.junit.jupiter.api.Nested\nimport org.junit.jupiter.api.Tag\nimport org.junit.jupiter.api.Test\nimport org.junit.jupiter.api.TestMethodOrder\nimport org.junit.jupiter.api.io.TempDir\nimport java.nio.file.Path\n\nimport com.saveourtool.diktat.ruleset.chapter3.spaces.IndentationConfigFactory as IndentationConfig\n\n/**\n * Legacy indentation tests.\n *\n * Consider adding new tests to [IndentationRuleTest] instead.\n *\n * @see IndentationRuleTest\n */\n@TestMethodOrder(NaturalDisplayName::class)\nclass IndentationRuleFixTest : FixTestBase(\"test/paragraph3/indentation\",\n    ::IndentationRule,\n    listOf(\n        RulesConfig(WRONG_INDENTATION.name, true,\n            mapOf(\n                NEWLINE_AT_END to \"true\",  // expected file should have two newlines at end in order to be read by BufferedReader correctly\n                EXTENDED_INDENT_OF_PARAMETERS to \"true\",\n                ALIGNED_PARAMETERS to \"true\",\n                EXTENDED_INDENT_FOR_EXPRESSION_BODIES to \"true\",\n                EXTENDED_INDENT_AFTER_OPERATORS to \"true\",\n                EXTENDED_INDENT_BEFORE_DOT to \"true\",\n            )\n        )\n    )\n) {\n    @Test\n    @Tag(WarningNames.WRONG_INDENTATION)\n    fun `parameters should be properly aligned`() {\n        fixAndCompare(\"IndentationParametersExpected.kt\", \"IndentationParametersTest.kt\")\n    }\n\n    @Test\n    @Tag(WarningNames.WRONG_INDENTATION)\n    fun `indentation rule - example 1`() {\n        fixAndCompare(\"IndentationFull1Expected.kt\", \"IndentationFull1Test.kt\")\n    }\n\n    @Test\n    @Tag(WarningNames.WRONG_INDENTATION)\n    fun `indentation rule - verbose example from ktlint`() {\n        fixAndCompare(\"IndentFullExpected.kt\", \"IndentFullTest.kt\")\n    }\n\n    @Test\n    @Tag(WarningNames.WRONG_INDENTATION)\n    fun `regression - incorrect fixing in constructor parameter list`() {\n        fixAndCompare(\"ConstructorExpected.kt\", \"ConstructorTest.kt\")\n    }\n\n    @Nested\n    @TestMethodOrder(NaturalDisplayName::class)\n    inner class `Multi-line string literals` {\n        /**\n         * Correctly-indented opening quotation mark, incorrectly-indented\n         * closing quotation mark.\n         */\n        @Test\n        @Tag(WarningNames.WRONG_INDENTATION)\n        @Suppress(\"LOCAL_VARIABLE_EARLY_DECLARATION\")  // False positives\n        fun `case 1 - mis-aligned opening and closing quotes`(@TempDir tempDir: Path) {\n            val actualCode = \"\"\"\n            |fun f() {\n            |    g(\n            |        \"\"${'\"'}\n            |            |val q = 1\n            |            |\n            |                    \"\"${'\"'}.trimMargin(),\n            |        arg1 = \"arg1\"\n            |    )\n            |}\n            \"\"\".trimMargin()\n\n            val expectedCode = \"\"\"\n            |fun f() {\n            |    g(\n            |        \"\"${'\"'}\n            |            |val q = 1\n            |            |\n            |        \"\"${'\"'}.trimMargin(),\n            |        arg1 = \"arg1\"\n            |    )\n            |}\n            \"\"\".trimMargin()\n\n            val lintResult = fixAndCompareContent(actualCode, expectedCode, tempDir)\n            lintResult.assertSuccessful()\n        }\n\n        /**\n         * Both the opening and the closing quotation marks are incorrectly\n         * indented (indentation level is less than needed).\n         */\n        @Test\n        @Tag(WarningNames.WRONG_INDENTATION)\n        @Suppress(\"LOCAL_VARIABLE_EARLY_DECLARATION\")  // False positives\n        fun `case 2`(@TempDir tempDir: Path) {\n            val actualCode = \"\"\"\n            |fun f() {\n            |    g(\n            |    \"\"${'\"'}\n            |            |val q = 1\n            |            |\n            |    \"\"${'\"'}.trimMargin(),\n            |        arg1 = \"arg1\"\n            |    )\n            |}\n            \"\"\".trimMargin()\n\n            val expectedCode = \"\"\"\n            |fun f() {\n            |    g(\n            |        \"\"${'\"'}\n            |                |val q = 1\n            |                |\n            |        \"\"${'\"'}.trimMargin(),\n            |        arg1 = \"arg1\"\n            |    )\n            |}\n            \"\"\".trimMargin()\n\n            val lintResult = fixAndCompareContent(actualCode, expectedCode, tempDir)\n            lintResult.assertSuccessful()\n        }\n\n        /**\n         * Both the opening and the closing quotation marks are incorrectly\n         * indented (indentation level is greater than needed).\n         */\n        @Test\n        @Tag(WarningNames.WRONG_INDENTATION)\n        @Suppress(\"LOCAL_VARIABLE_EARLY_DECLARATION\")  // False positives\n        fun `case 3`(@TempDir tempDir: Path) {\n            val actualCode = \"\"\"\n            |fun f() {\n            |    g(\n            |            \"\"${'\"'}\n            |                    |val q = 1\n            |                    |\n            |            \"\"${'\"'}.trimMargin(),\n            |        arg1 = \"arg1\"\n            |    )\n            |}\n            \"\"\".trimMargin()\n\n            val expectedCode = \"\"\"\n            |fun f() {\n            |    g(\n            |        \"\"${'\"'}\n            |                |val q = 1\n            |                |\n            |        \"\"${'\"'}.trimMargin(),\n            |        arg1 = \"arg1\"\n            |    )\n            |}\n            \"\"\".trimMargin()\n\n            val lintResult = fixAndCompareContent(actualCode, expectedCode, tempDir)\n            lintResult.assertSuccessful()\n        }\n\n        /**\n         * Both the opening and the closing quotation marks are incorrectly\n         * indented and misaligned.\n         */\n        @Test\n        @Tag(WarningNames.WRONG_INDENTATION)\n        @Suppress(\"LOCAL_VARIABLE_EARLY_DECLARATION\")  // False positives\n        fun `case 4 - mis-aligned opening and closing quotes`(@TempDir tempDir: Path) {\n            val actualCode = \"\"\"\n            |fun f() {\n            |    g(\n            |            \"\"${'\"'}\n            |                    |val q = 1\n            |                    |\n            |                            \"\"${'\"'}.trimMargin(),\n            |        arg1 = \"arg1\"\n            |    )\n            |}\n            \"\"\".trimMargin()\n\n            val expectedCode = \"\"\"\n            |fun f() {\n            |    g(\n            |        \"\"${'\"'}\n            |                |val q = 1\n            |                |\n            |        \"\"${'\"'}.trimMargin(),\n            |        arg1 = \"arg1\"\n            |    )\n            |}\n            \"\"\".trimMargin()\n\n            val lintResult = fixAndCompareContent(actualCode, expectedCode, tempDir)\n            lintResult.assertSuccessful()\n        }\n\n        private fun fixAndCompareContent(@Language(\"kotlin\") actualCode: String,\n                                         @Language(\"kotlin\") expectedCode: String,\n                                         tempDir: Path\n        ): TestFileContent {\n            val config = IndentationConfig(NEWLINE_AT_END to false).withCustomParameters().asRulesConfigList()\n            return fixAndCompareContent(actualCode, expectedCode, tempDir, overrideRulesConfigList = config)\n        }\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/test/kotlin/com/saveourtool/diktat/ruleset/chapter3/spaces/IndentationRuleTest.kt",
    "content": "@file:Suppress(\"FILE_IS_TOO_LONG\")\n\npackage com.saveourtool.diktat.ruleset.chapter3.spaces\n\nimport com.saveourtool.diktat.ruleset.chapter3.spaces.junit.IndentationTest\nimport com.saveourtool.diktat.ruleset.chapter3.spaces.junit.IndentedSourceCode\nimport com.saveourtool.diktat.ruleset.junit.BooleanOrDefault.FALSE\nimport com.saveourtool.diktat.ruleset.junit.BooleanOrDefault.TRUE\nimport com.saveourtool.diktat.ruleset.junit.NaturalDisplayName\nimport org.junit.jupiter.api.Nested\nimport org.junit.jupiter.api.TestMethodOrder\n\n/**\n * For legacy indentation tests, see [IndentationRuleWarnTest] and\n * [IndentationRuleFixTest].\n *\n * @see IndentationRuleWarnTest\n * @see IndentationRuleFixTest\n */\n@Suppress(\n    \"LargeClass\",\n    \"MaxLineLength\",\n    \"LONG_LINE\",\n)\n@TestMethodOrder(NaturalDisplayName::class)\nclass IndentationRuleTest {\n    /**\n     * See [#1330](https://github.com/saveourtool/diktat/issues/1330).\n     */\n    @Nested\n    @TestMethodOrder(NaturalDisplayName::class)\n    inner class `Expression body functions` {\n        @IndentationTest(\n            first = IndentedSourceCode(\n                \"\"\"\n                @Test\n                fun `checking that suppression with ignore everything works`() {\n                    val code =\n                        \"\"${'\"'} // diktat:WRONG_INDENTATION[expectedIndent = 12]\n                            @Suppress(\"diktat\")\n                            fun foo() {\n                                val a = 1\n                            }\n                        \"\"${'\"'}.trimIndent()\n                    lintMethod(code)\n                }\n                \"\"\",\n                extendedIndentForExpressionBodies = FALSE),\n            second = IndentedSourceCode(\n                \"\"\"\n                @Test\n                fun `checking that suppression with ignore everything works`() {\n                    val code =\n                            \"\"${'\"'} // diktat:WRONG_INDENTATION[expectedIndent = 8]\n                                @Suppress(\"diktat\")\n                                fun foo() {\n                                    val a = 1\n                                }\n                            \"\"${'\"'}.trimIndent()\n                    lintMethod(code)\n                }\n                \"\"\",\n                extendedIndentForExpressionBodies = TRUE))\n        fun `case 1`() = Unit\n\n        @IndentationTest(\n            first = IndentedSourceCode(\n                \"\"\"\n                val currentTime: Time\n                    get() =\n                        with(currentDateTime) {                                 // diktat:WRONG_INDENTATION[expectedIndent = 12]\n                            Time(hour = hour, minute = minute, second = second) // diktat:WRONG_INDENTATION[expectedIndent = 16]\n                        }                                                       // diktat:WRONG_INDENTATION[expectedIndent = 12]\n                \"\"\",\n                extendedIndentForExpressionBodies = FALSE),\n            second = IndentedSourceCode(\n                \"\"\"\n                val currentTime: Time\n                    get() =\n                            with(currentDateTime) {                                 // diktat:WRONG_INDENTATION[expectedIndent = 8]\n                                Time(hour = hour, minute = minute, second = second) // diktat:WRONG_INDENTATION[expectedIndent = 12]\n                            }                                                       // diktat:WRONG_INDENTATION[expectedIndent = 8]\n                \"\"\",\n                extendedIndentForExpressionBodies = TRUE))\n        fun `case 2`() = Unit\n\n        @IndentationTest(\n            first = IndentedSourceCode(\n                \"\"\"\n                fun formatDateByPattern(date: String, pattern: String = \"ddMMyy\"): String =\n                    DateTimeFormatter.ofPattern(pattern).format(LocalDate.parse(date)) // diktat:WRONG_INDENTATION[expectedIndent = 8]\n                \"\"\",\n                extendedIndentForExpressionBodies = FALSE),\n            second = IndentedSourceCode(\n                \"\"\"\n                fun formatDateByPattern(date: String, pattern: String = \"ddMMyy\"): String =\n                        DateTimeFormatter.ofPattern(pattern).format(LocalDate.parse(date)) // diktat:WRONG_INDENTATION[expectedIndent = 4]\n                \"\"\",\n                extendedIndentForExpressionBodies = TRUE))\n        fun `case 3`() = Unit\n\n        @IndentationTest(\n            first = IndentedSourceCode(\n                \"\"\"\n                private fun createLayoutParams(): WindowManager.LayoutParams =\n                    WindowManager.LayoutParams().apply { /* ... */ } // diktat:WRONG_INDENTATION[expectedIndent = 8]\n                \"\"\",\n                extendedIndentForExpressionBodies = FALSE),\n            second = IndentedSourceCode(\n                \"\"\"\n                private fun createLayoutParams(): WindowManager.LayoutParams =\n                        WindowManager.LayoutParams().apply { /* ... */ } // diktat:WRONG_INDENTATION[expectedIndent = 4]\n                \"\"\",\n                extendedIndentForExpressionBodies = TRUE))\n        fun `case 4`() = Unit\n\n        @IndentationTest(\n            first = IndentedSourceCode(\n                \"\"\"\n                private fun createLayoutParams(): WindowManager.LayoutParams =\n                    WindowManager.LayoutParams().apply {                                                                                     // diktat:WRONG_INDENTATION[expectedIndent = 8]\n                        type = WindowManager.LayoutParams.TYPE_APPLICATION_PANEL                                                             // diktat:WRONG_INDENTATION[expectedIndent = 12]\n                        token = composeView.applicationWindowToken                                                                           // diktat:WRONG_INDENTATION[expectedIndent = 12]\n                        width = WindowManager.LayoutParams.MATCH_PARENT                                                                      // diktat:WRONG_INDENTATION[expectedIndent = 12]\n                        height = WindowManager.LayoutParams.MATCH_PARENT                                                                     // diktat:WRONG_INDENTATION[expectedIndent = 12]\n                        format = PixelFormat.TRANSLUCENT                                                                                     // diktat:WRONG_INDENTATION[expectedIndent = 12]\n\n                        // TODO make composable configurable                                                                                 // diktat:WRONG_INDENTATION[expectedIndent = 12]\n\n                        // see https://stackoverflow.com/questions/43511326/android-making-activity-full-screen-with-status-bar-on-top-of-it // diktat:WRONG_INDENTATION[expectedIndent = 12]\n                        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {                                                                // diktat:WRONG_INDENTATION[expectedIndent = 12]\n                            windowInsetsController?.hide(WindowInsets.Type.statusBars())                                                     // diktat:WRONG_INDENTATION[expectedIndent = 16]\n                        } else {                                                                                                             // diktat:WRONG_INDENTATION[expectedIndent = 12]\n                            @Suppress(\"DEPRECATION\")                                                                                         // diktat:WRONG_INDENTATION[expectedIndent = 16]\n                            systemUiVisibility = (View.SYSTEM_UI_FLAG_LOW_PROFILE or                                                         // diktat:WRONG_INDENTATION[expectedIndent = 16]\n                                    View.SYSTEM_UI_FLAG_FULLSCREEN or\n                                    View.SYSTEM_UI_FLAG_LAYOUT_STABLE or\n                                    View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY or\n                                    View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION or\n                                    View.SYSTEM_UI_FLAG_HIDE_NAVIGATION)\n                        }                                                                                                                    // diktat:WRONG_INDENTATION[expectedIndent = 12]\n                    }                                                                                                                        // diktat:WRONG_INDENTATION[expectedIndent = 8]\n                \"\"\",\n                extendedIndentForExpressionBodies = FALSE),\n            second = IndentedSourceCode(\n                \"\"\"\n                private fun createLayoutParams(): WindowManager.LayoutParams =\n                        WindowManager.LayoutParams().apply {                                                                                     // diktat:WRONG_INDENTATION[expectedIndent = 4]\n                            type = WindowManager.LayoutParams.TYPE_APPLICATION_PANEL                                                             // diktat:WRONG_INDENTATION[expectedIndent = 8]\n                            token = composeView.applicationWindowToken                                                                           // diktat:WRONG_INDENTATION[expectedIndent = 8]\n                            width = WindowManager.LayoutParams.MATCH_PARENT                                                                      // diktat:WRONG_INDENTATION[expectedIndent = 8]\n                            height = WindowManager.LayoutParams.MATCH_PARENT                                                                     // diktat:WRONG_INDENTATION[expectedIndent = 8]\n                            format = PixelFormat.TRANSLUCENT                                                                                     // diktat:WRONG_INDENTATION[expectedIndent = 8]\n\n                            // TODO make composable configurable                                                                                 // diktat:WRONG_INDENTATION[expectedIndent = 8]\n\n                            // see https://stackoverflow.com/questions/43511326/android-making-activity-full-screen-with-status-bar-on-top-of-it // diktat:WRONG_INDENTATION[expectedIndent = 8]\n                            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {                                                                // diktat:WRONG_INDENTATION[expectedIndent = 8]\n                                windowInsetsController?.hide(WindowInsets.Type.statusBars())                                                     // diktat:WRONG_INDENTATION[expectedIndent = 12]\n                            } else {                                                                                                             // diktat:WRONG_INDENTATION[expectedIndent = 8]\n                                @Suppress(\"DEPRECATION\")                                                                                         // diktat:WRONG_INDENTATION[expectedIndent = 12]\n                                systemUiVisibility = (View.SYSTEM_UI_FLAG_LOW_PROFILE or                                                         // diktat:WRONG_INDENTATION[expectedIndent = 12]\n                                        View.SYSTEM_UI_FLAG_FULLSCREEN or\n                                        View.SYSTEM_UI_FLAG_LAYOUT_STABLE or\n                                        View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY or\n                                        View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION or\n                                        View.SYSTEM_UI_FLAG_HIDE_NAVIGATION)\n                            }                                                                                                                    // diktat:WRONG_INDENTATION[expectedIndent = 8]\n                        }                                                                                                                        // diktat:WRONG_INDENTATION[expectedIndent = 4]\n                \"\"\",\n                extendedIndentForExpressionBodies = TRUE))\n        fun `case 5`() = Unit\n\n        @IndentationTest(\n            first = IndentedSourceCode(\n                \"\"\"\n                val offsetDelta =\n                    if (shimmerAnimationType != ShimmerAnimationType.FADE) translateAnim.dp // diktat:WRONG_INDENTATION[expectedIndent = 8]\n                    else 2000.dp                                                            // diktat:WRONG_INDENTATION[expectedIndent = 8]\n                \"\"\",\n                extendedIndentForExpressionBodies = FALSE),\n            second = IndentedSourceCode(\n                \"\"\"\n                val offsetDelta =\n                        if (shimmerAnimationType != ShimmerAnimationType.FADE) translateAnim.dp // diktat:WRONG_INDENTATION[expectedIndent = 4]\n                        else 2000.dp                                                            // diktat:WRONG_INDENTATION[expectedIndent = 4]\n                \"\"\",\n                extendedIndentForExpressionBodies = TRUE))\n        fun `case 6`() = Unit\n\n        @IndentationTest(\n            first = IndentedSourceCode(\n                \"\"\"\n                private fun lerp(start: Float, stop: Float, fraction: Float): Float =\n                    (1 - fraction) * start + fraction * stop // diktat:WRONG_INDENTATION[expectedIndent = 8]\n                \"\"\",\n                extendedIndentForExpressionBodies = FALSE),\n            second = IndentedSourceCode(\n                \"\"\"\n                private fun lerp(start: Float, stop: Float, fraction: Float): Float =\n                        (1 - fraction) * start + fraction * stop // diktat:WRONG_INDENTATION[expectedIndent = 4]\n                \"\"\",\n                extendedIndentForExpressionBodies = TRUE))\n        fun `case 7`() = Unit\n\n        @IndentationTest(\n            first = IndentedSourceCode(\n                \"\"\"\n                fun foo() =\n                    println() // diktat:WRONG_INDENTATION[expectedIndent = 8]\n                \"\"\",\n                extendedIndentForExpressionBodies = FALSE),\n            second = IndentedSourceCode(\n                \"\"\"\n                fun foo() =\n                        println() // diktat:WRONG_INDENTATION[expectedIndent = 4]\n                \"\"\",\n                extendedIndentForExpressionBodies = TRUE))\n        fun `case 8`() = Unit\n\n        @IndentationTest(\n            first = IndentedSourceCode(\n                \"\"\"\n                fun f() =\n                    x + (y +     // diktat:WRONG_INDENTATION[expectedIndent = 8]\n                            g(x)\n                    )            // diktat:WRONG_INDENTATION[expectedIndent = 8]\n                \"\"\",\n                extendedIndentForExpressionBodies = FALSE),\n            second = IndentedSourceCode(\n                \"\"\"\n                fun f() =\n                        x + (y +     // diktat:WRONG_INDENTATION[expectedIndent = 4]\n                                g(x)\n                        )            // diktat:WRONG_INDENTATION[expectedIndent = 4]\n                \"\"\",\n                extendedIndentForExpressionBodies = TRUE))\n        fun `case 9`() = Unit\n\n        @IndentationTest(\n            first = IndentedSourceCode(\n                \"\"\"\n                fun f() =\n                    (1 +       // diktat:WRONG_INDENTATION[expectedIndent = 8]\n                            2)\n                \"\"\",\n                extendedIndentForExpressionBodies = FALSE),\n            second = IndentedSourceCode(\n                \"\"\"\n                fun f() =\n                        (1 +       // diktat:WRONG_INDENTATION[expectedIndent = 4]\n                                2)\n                \"\"\",\n                extendedIndentForExpressionBodies = TRUE))\n        fun `case 10`() = Unit\n    }\n\n    @Nested\n    @TestMethodOrder(NaturalDisplayName::class)\n    inner class `String templates` {\n        /**\n         * No message like\n         *\n         * > only spaces are allowed for indentation and each indentation should\n         * > equal to 4 spaces (tabs are not allowed): the same number of\n         * > indents to the opening and closing quotes was expected\n         *\n         * should be reported.\n         *\n         * See [#1490](https://github.com/saveourtool/diktat/issues/1490).\n         */\n        @IndentationTest(IndentedSourceCode(\n            \"\"\"\n            val value = f(\n                \"text ${'$'}variable text\".isEmpty()\n            )\n            \"\"\"),\n            singleConfiguration = true)\n        fun `mis-aligned opening and closing quotes of a string template, false positive, case 1 (#1490)`() = Unit\n\n        /**\n         * No message like\n         *\n         * > only spaces are allowed for indentation and each indentation should\n         * > equal to 4 spaces (tabs are not allowed): the same number of\n         * > indents to the opening and closing quotes was expected\n         *\n         * should be reported.\n         *\n         * See [#1490](https://github.com/saveourtool/diktat/issues/1490).\n         */\n        @IndentationTest(IndentedSourceCode(\n            \"\"\"\n            val value = f(\n                \"text ${'$'}variable text\".trimIndent()\n            )\n            \"\"\"),\n            singleConfiguration = true)\n        fun `mis-aligned opening and closing quotes of a string template, false positive, case 2 (#1490)`() = Unit\n\n        /**\n         * No message like\n         *\n         * > only spaces are allowed for indentation and each indentation should\n         * > equal to 4 spaces (tabs are not allowed): the same number of\n         * > indents to the opening and closing quotes was expected\n         *\n         * should be reported.\n         *\n         * See [#1490](https://github.com/saveourtool/diktat/issues/1490).\n         */\n        @IndentationTest(IndentedSourceCode(\n            \"\"\"\n            val value = f(\n                \"text ${'$'}variable text\".trimMargin()\n            )\n            \"\"\"),\n            singleConfiguration = true)\n        fun `mis-aligned opening and closing quotes of a string template, false positive, case 3 (#1490)`() = Unit\n    }\n\n    /**\n     * See [#1347](https://github.com/saveourtool/diktat/issues/1347).\n     */\n    @Nested\n    @TestMethodOrder(NaturalDisplayName::class)\n    inner class `Multi-line string literals` {\n        @IndentationTest(\n            first = IndentedSourceCode(\n                \"\"\"\n                @Test\n                fun `test method name`() {\n                    @Language(\"kotlin\")\n                    val code =\n                        \"\"${'\"'}\n                            @Suppress(\"diktat\")\n                            fun foo() {\n                                val a = 1\n                            }\n                        \"\"${'\"'}.trimIndent()\n                    lintMethod(code)\n                }\n                \"\"\",\n                extendedIndentOfParameters = FALSE,\n                extendedIndentForExpressionBodies = FALSE,\n                extendedIndentAfterOperators = FALSE,\n                extendedIndentBeforeDot = FALSE),\n            second = IndentedSourceCode(\n                \"\"\"\n                @Test\n                fun `test method name`() {\n                    @Language(\"kotlin\")\n                    val code =\n                            \"\"${'\"'}\n                                @Suppress(\"diktat\")\n                                fun foo() {\n                                    val a = 1\n                                }\n                            \"\"${'\"'}.trimIndent()\n                    lintMethod(code)\n                }\n                \"\"\",\n                extendedIndentOfParameters = TRUE,\n                extendedIndentForExpressionBodies = TRUE,\n                extendedIndentAfterOperators = TRUE,\n                extendedIndentBeforeDot = TRUE),\n            includeWarnTests = false\n        )\n        fun `no whitespace should be injected, case 1`() = Unit\n\n        @IndentationTest(\n            first = IndentedSourceCode(\n                \"\"\"\n                fun f0() {\n                    @Language(\"kotlin\")\n                    val code =\n                        \"\"${'\"'}\n                            |@Suppress(\"diktat\")\n                            |fun foo() {\n                            |    val a = 1\n                            |}\n                        \"\"${'\"'}.trimMargin()\n                    lintMethod(code)\n                }\n                \"\"\",\n                extendedIndentOfParameters = FALSE,\n                extendedIndentForExpressionBodies = FALSE,\n                extendedIndentAfterOperators = FALSE,\n                extendedIndentBeforeDot = FALSE),\n            second = IndentedSourceCode(\n                \"\"\"\n                fun f0() {\n                    @Language(\"kotlin\")\n                    val code =\n                            \"\"${'\"'}\n                                |@Suppress(\"diktat\")\n                                |fun foo() {\n                                |    val a = 1\n                                |}\n                            \"\"${'\"'}.trimMargin()\n                    lintMethod(code)\n                }\n                \"\"\",\n                extendedIndentOfParameters = TRUE,\n                extendedIndentForExpressionBodies = TRUE,\n                extendedIndentAfterOperators = TRUE,\n                extendedIndentBeforeDot = TRUE),\n            includeWarnTests = false\n        )\n        fun `no whitespace should be injected, case 2`() = Unit\n\n        @IndentationTest(\n            first = IndentedSourceCode(\n                \"\"\"\n                fun f1() {\n                    @Language(\"kotlin\")\n                    val code =\n                        \"\"${'\"'}\n                            |@Suppress(\"diktat\")\n                            |fun foo() {\n                            |    val a = 1\n                            |}\n                        \"\"${'\"'}.trimMargin(\"|\")\n                    lintMethod(code)\n                }\n                \"\"\",\n                extendedIndentOfParameters = FALSE,\n                extendedIndentForExpressionBodies = FALSE,\n                extendedIndentAfterOperators = FALSE,\n                extendedIndentBeforeDot = FALSE),\n            second = IndentedSourceCode(\n                \"\"\"\n                fun f1() {\n                    @Language(\"kotlin\")\n                    val code =\n                            \"\"${'\"'}\n                                |@Suppress(\"diktat\")\n                                |fun foo() {\n                                |    val a = 1\n                                |}\n                            \"\"${'\"'}.trimMargin(\"|\")\n                    lintMethod(code)\n                }\n                \"\"\",\n                extendedIndentOfParameters = TRUE,\n                extendedIndentForExpressionBodies = TRUE,\n                extendedIndentAfterOperators = TRUE,\n                extendedIndentBeforeDot = TRUE),\n            includeWarnTests = false\n        )\n        fun `no whitespace should be injected, case 3`() = Unit\n\n        @IndentationTest(\n            first = IndentedSourceCode(\n                \"\"\"\n                fun f2() {\n                    @Language(\"kotlin\")\n                    val code =\n                        \"\"${'\"'}\n                            >@Suppress(\"diktat\")\n                            >fun foo() {\n                            >    val a = 1\n                            >}\n                        \"\"${'\"'} . trimMargin ( marginPrefix = \">\" )\n                    lintMethod(code)\n                }\n                \"\"\",\n                extendedIndentOfParameters = FALSE,\n                extendedIndentForExpressionBodies = FALSE,\n                extendedIndentAfterOperators = FALSE,\n                extendedIndentBeforeDot = FALSE),\n            second = IndentedSourceCode(\n                \"\"\"\n                fun f2() {\n                    @Language(\"kotlin\")\n                    val code =\n                            \"\"${'\"'}\n                                >@Suppress(\"diktat\")\n                                >fun foo() {\n                                >    val a = 1\n                                >}\n                            \"\"${'\"'} . trimMargin ( marginPrefix = \">\" )\n                    lintMethod(code)\n                }\n                \"\"\",\n                extendedIndentOfParameters = TRUE,\n                extendedIndentForExpressionBodies = TRUE,\n                extendedIndentAfterOperators = TRUE,\n                extendedIndentBeforeDot = TRUE),\n            includeWarnTests = false\n        )\n        fun `no whitespace should be injected, case 4`() = Unit\n\n        @IndentationTest(\n            first = IndentedSourceCode(\n                \"\"\"\n                fun checkScript() {\n                    lintMethod(\n                        \"\"${'\"'}\n                                    |val A = \"aa\"\n                        \"\"${'\"'}.trimMargin(),\n                    )\n                }\n                \"\"\",\n                extendedIndentOfParameters = FALSE,\n                extendedIndentForExpressionBodies = FALSE,\n                extendedIndentAfterOperators = FALSE,\n                extendedIndentBeforeDot = FALSE),\n            second = IndentedSourceCode(\n                \"\"\"\n                fun checkScript() {\n                    lintMethod(\n                            \"\"${'\"'}\n                                        |val A = \"aa\"\n                            \"\"${'\"'}.trimMargin(),\n                    )\n                }\n                \"\"\",\n                extendedIndentOfParameters = TRUE,\n                extendedIndentForExpressionBodies = TRUE,\n                extendedIndentAfterOperators = TRUE,\n                extendedIndentBeforeDot = TRUE),\n            includeWarnTests = false\n        )\n        fun `no whitespace should be injected, case 5`() = Unit\n    }\n\n    /**\n     * Expressions wrapped on an operator or an infix function.\n     *\n     * See [#1340](https://github.com/saveourtool/diktat/issues/1340).\n     */\n    @Nested\n    @TestMethodOrder(NaturalDisplayName::class)\n    inner class `Expressions wrapped after operator` {\n        @IndentationTest(\n            first = IndentedSourceCode(\n                \"\"\"\n                fun f() {\n                    systemUiVisibility = View.SYSTEM_UI_FLAG_LOW_PROFILE or\n                        View.SYSTEM_UI_FLAG_FULLSCREEN or // diktat:WRONG_INDENTATION[expectedIndent = 12]\n                        View.SYSTEM_UI_FLAG_LAYOUT_STABLE or // diktat:WRONG_INDENTATION[expectedIndent = 12]\n                        View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY or // diktat:WRONG_INDENTATION[expectedIndent = 12]\n                        View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION or // diktat:WRONG_INDENTATION[expectedIndent = 12]\n                        View.SYSTEM_UI_FLAG_HIDE_NAVIGATION // diktat:WRONG_INDENTATION[expectedIndent = 12]\n                }\n                \"\"\",\n                extendedIndentAfterOperators = FALSE),\n            second = IndentedSourceCode(\n                \"\"\"\n                fun f() {\n                    systemUiVisibility = View.SYSTEM_UI_FLAG_LOW_PROFILE or\n                            View.SYSTEM_UI_FLAG_FULLSCREEN or // diktat:WRONG_INDENTATION[expectedIndent = 8]\n                            View.SYSTEM_UI_FLAG_LAYOUT_STABLE or // diktat:WRONG_INDENTATION[expectedIndent = 8]\n                            View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY or // diktat:WRONG_INDENTATION[expectedIndent = 8]\n                            View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION or // diktat:WRONG_INDENTATION[expectedIndent = 8]\n                            View.SYSTEM_UI_FLAG_HIDE_NAVIGATION // diktat:WRONG_INDENTATION[expectedIndent = 8]\n                }\n                \"\"\",\n                extendedIndentAfterOperators = TRUE))\n        fun `case 1`() = Unit\n\n        @IndentationTest(\n            first = IndentedSourceCode(\n                \"\"\"\n                val systemUiVisibility = View.SYSTEM_UI_FLAG_LOW_PROFILE or\n                    View.SYSTEM_UI_FLAG_FULLSCREEN or // diktat:WRONG_INDENTATION[expectedIndent = 8]\n                    View.SYSTEM_UI_FLAG_LAYOUT_STABLE or // diktat:WRONG_INDENTATION[expectedIndent = 8]\n                    View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY or // diktat:WRONG_INDENTATION[expectedIndent = 8]\n                    View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION or // diktat:WRONG_INDENTATION[expectedIndent = 8]\n                    View.SYSTEM_UI_FLAG_HIDE_NAVIGATION // diktat:WRONG_INDENTATION[expectedIndent = 8]\n                \"\"\",\n                extendedIndentAfterOperators = FALSE),\n            second = IndentedSourceCode(\n                \"\"\"\n                val systemUiVisibility = View.SYSTEM_UI_FLAG_LOW_PROFILE or\n                        View.SYSTEM_UI_FLAG_FULLSCREEN or // diktat:WRONG_INDENTATION[expectedIndent = 4]\n                        View.SYSTEM_UI_FLAG_LAYOUT_STABLE or // diktat:WRONG_INDENTATION[expectedIndent = 4]\n                        View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY or // diktat:WRONG_INDENTATION[expectedIndent = 4]\n                        View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION or // diktat:WRONG_INDENTATION[expectedIndent = 4]\n                        View.SYSTEM_UI_FLAG_HIDE_NAVIGATION // diktat:WRONG_INDENTATION[expectedIndent = 4]\n                \"\"\",\n                extendedIndentAfterOperators = TRUE))\n        fun `case 2`() = Unit\n\n        @IndentationTest(\n            first = IndentedSourceCode(\n                \"\"\"\n                const val FOO = 1\n\n                const val BAR = 2\n\n                const val BAZ = 4\n\n                fun acceptInteger(arg: Int) = Unit\n\n                fun main() {\n                    acceptInteger(FOO or BAR or BAZ or FOO or BAR or BAZ or\n                        FOO or BAR or BAZ or FOO or BAR or BAZ or FOO or BAR or BAZ or // diktat:WRONG_INDENTATION[expectedIndent = 12]\n                        FOO or BAR or BAZ) // diktat:WRONG_INDENTATION[expectedIndent = 12]\n                }\n                \"\"\",\n                extendedIndentAfterOperators = FALSE),\n            second = IndentedSourceCode(\n                \"\"\"\n                const val FOO = 1\n\n                const val BAR = 2\n\n                const val BAZ = 4\n\n                fun acceptInteger(arg: Int) = Unit\n\n                fun main() {\n                    acceptInteger(FOO or BAR or BAZ or FOO or BAR or BAZ or\n                            FOO or BAR or BAZ or FOO or BAR or BAZ or FOO or BAR or BAZ or // diktat:WRONG_INDENTATION[expectedIndent = 8]\n                            FOO or BAR or BAZ) // diktat:WRONG_INDENTATION[expectedIndent = 8]\n                }\n                \"\"\",\n                extendedIndentAfterOperators = TRUE))\n        fun `case 3`() = Unit\n\n        @IndentationTest(\n            first = IndentedSourceCode(\n                \"\"\"\n                const val TRUE = true\n\n                const val FALSE = false\n\n                fun acceptBoolean(arg: Boolean) = Unit\n\n                fun f() {\n                    acceptBoolean(TRUE ||\n                        FALSE || // diktat:WRONG_INDENTATION[expectedIndent = 12]\n                        TRUE) // diktat:WRONG_INDENTATION[expectedIndent = 12]\n                }\n                \"\"\",\n                extendedIndentAfterOperators = FALSE),\n            second = IndentedSourceCode(\n                \"\"\"\n                const val TRUE = true\n\n                const val FALSE = false\n\n                fun acceptBoolean(arg: Boolean) = Unit\n\n                fun f() {\n                    acceptBoolean(TRUE ||\n                            FALSE || // diktat:WRONG_INDENTATION[expectedIndent = 8]\n                            TRUE) // diktat:WRONG_INDENTATION[expectedIndent = 8]\n                }\n                \"\"\",\n                extendedIndentAfterOperators = TRUE))\n        fun `case 4`() = Unit\n\n        @IndentationTest(\n            first = IndentedSourceCode(\n                \"\"\"\n                val c = 3 +\n                    2 // diktat:WRONG_INDENTATION[expectedIndent = 8]\n                \"\"\",\n                extendedIndentAfterOperators = FALSE),\n            second = IndentedSourceCode(\n                \"\"\"\n                val c = 3 +\n                        2 // diktat:WRONG_INDENTATION[expectedIndent = 4]\n                \"\"\",\n                extendedIndentAfterOperators = TRUE))\n        fun `case 5`() = Unit\n\n        @IndentationTest(\n            first = IndentedSourceCode(\n                \"\"\"\n                infix fun Int.combineWith(that: Int) = this + that\n\n                fun f() {\n                    val x = 1 combineWith\n                        2 combineWith // diktat:WRONG_INDENTATION[expectedIndent = 12]\n                        3 combineWith // diktat:WRONG_INDENTATION[expectedIndent = 12]\n                        4 combineWith // diktat:WRONG_INDENTATION[expectedIndent = 12]\n                        5 combineWith // diktat:WRONG_INDENTATION[expectedIndent = 12]\n                        6 // diktat:WRONG_INDENTATION[expectedIndent = 12]\n                }\n                \"\"\",\n                extendedIndentAfterOperators = FALSE),\n            second = IndentedSourceCode(\n                \"\"\"\n                infix fun Int.combineWith(that: Int) = this + that\n\n                fun f() {\n                    val x = 1 combineWith\n                            2 combineWith // diktat:WRONG_INDENTATION[expectedIndent = 8]\n                            3 combineWith // diktat:WRONG_INDENTATION[expectedIndent = 8]\n                            4 combineWith // diktat:WRONG_INDENTATION[expectedIndent = 8]\n                            5 combineWith // diktat:WRONG_INDENTATION[expectedIndent = 8]\n                            6 // diktat:WRONG_INDENTATION[expectedIndent = 8]\n                }\n                \"\"\",\n                extendedIndentAfterOperators = TRUE))\n        fun `case 6`() = Unit\n\n        @IndentationTest(\n            first = IndentedSourceCode(\n                \"\"\"\n                fun f(i1: Int, i2: Int, i3: Int): Int {\n                    if (i2 > 0 &&\n                        i3 < 0) { // diktat:WRONG_INDENTATION[expectedIndent = 12]\n                        return 2\n                    }\n                    return 0\n                }\n                \"\"\",\n                extendedIndentAfterOperators = FALSE),\n            second = IndentedSourceCode(\n                \"\"\"\n                fun f(i1: Int, i2: Int, i3: Int): Int {\n                    if (i2 > 0 &&\n                            i3 < 0) { // diktat:WRONG_INDENTATION[expectedIndent = 8]\n                        return 2\n                    }\n                    return 0\n                }\n                \"\"\",\n                extendedIndentAfterOperators = TRUE))\n        fun `case 7`() = Unit\n\n        @IndentationTest(\n            first = IndentedSourceCode(\n                \"\"\"\n                val value1 = 1 to\n                    2 to // diktat:WRONG_INDENTATION[expectedIndent = 8]\n                    3 // diktat:WRONG_INDENTATION[expectedIndent = 8]\n                \"\"\",\n                extendedIndentAfterOperators = FALSE),\n            second = IndentedSourceCode(\n                \"\"\"\n                val value1 = 1 to\n                        2 to // diktat:WRONG_INDENTATION[expectedIndent = 4]\n                        3 // diktat:WRONG_INDENTATION[expectedIndent = 4]\n                \"\"\",\n                extendedIndentAfterOperators = TRUE))\n        fun `case 8`() = Unit\n\n        @IndentationTest(\n            first = IndentedSourceCode(\n                \"\"\"\n                val value1a = (1 to\n                    2 to // diktat:WRONG_INDENTATION[expectedIndent = 8]\n                    3) // diktat:WRONG_INDENTATION[expectedIndent = 8]\n                \"\"\",\n                extendedIndentAfterOperators = FALSE),\n            second = IndentedSourceCode(\n                \"\"\"\n                val value1a = (1 to\n                        2 to // diktat:WRONG_INDENTATION[expectedIndent = 4]\n                        3) // diktat:WRONG_INDENTATION[expectedIndent = 4]\n                \"\"\",\n                extendedIndentAfterOperators = TRUE))\n        fun `case 9`() = Unit\n\n        @IndentationTest(\n            first = IndentedSourceCode(\n                \"\"\"\n                val value2 =\n                    1 to\n                        2 to // diktat:WRONG_INDENTATION[expectedIndent = 12]\n                        3 // diktat:WRONG_INDENTATION[expectedIndent = 12]\n                \"\"\",\n                extendedIndentAfterOperators = FALSE),\n            second = IndentedSourceCode(\n                \"\"\"\n                val value2 =\n                    1 to\n                            2 to // diktat:WRONG_INDENTATION[expectedIndent = 8]\n                            3 // diktat:WRONG_INDENTATION[expectedIndent = 8]\n                \"\"\",\n                extendedIndentAfterOperators = TRUE))\n        fun `case 10`() = Unit\n\n        @IndentationTest(\n            first = IndentedSourceCode(\n                \"\"\"\n                val value3 =\n                    (1 to\n                        2 to // diktat:WRONG_INDENTATION[expectedIndent = 12]\n                        3) // diktat:WRONG_INDENTATION[expectedIndent = 12]\n                \"\"\",\n                extendedIndentAfterOperators = FALSE),\n            second = IndentedSourceCode(\n                \"\"\"\n                val value3 =\n                    (1 to\n                            2 to // diktat:WRONG_INDENTATION[expectedIndent = 8]\n                            3) // diktat:WRONG_INDENTATION[expectedIndent = 8]\n                \"\"\",\n                extendedIndentAfterOperators = TRUE))\n        fun `case 11`() = Unit\n\n        @IndentationTest(\n            first = IndentedSourceCode(\n                \"\"\"\n                fun <T : Any> identity(t: T): T = t\n\n                val value4 = identity(1 to\n                    2 to // diktat:WRONG_INDENTATION[expectedIndent = 8]\n                    3) // diktat:WRONG_INDENTATION[expectedIndent = 8]\n                \"\"\",\n                extendedIndentAfterOperators = FALSE),\n            second = IndentedSourceCode(\n                \"\"\"\n                fun <T : Any> identity(t: T): T = t\n\n                val value4 = identity(1 to\n                        2 to // diktat:WRONG_INDENTATION[expectedIndent = 4]\n                        3) // diktat:WRONG_INDENTATION[expectedIndent = 4]\n                \"\"\",\n                extendedIndentAfterOperators = TRUE))\n        fun `case 12`() = Unit\n\n        @IndentationTest(\n            first = IndentedSourceCode(\n                \"\"\"\n                fun <T : Any> identity(t: T): T = t\n\n                val value5 = identity(\n                    1 to\n                        2 to // diktat:WRONG_INDENTATION[expectedIndent = 12]\n                        3) // diktat:WRONG_INDENTATION[expectedIndent = 12]\n                \"\"\",\n                extendedIndentAfterOperators = FALSE),\n            second = IndentedSourceCode(\n                \"\"\"\n                fun <T : Any> identity(t: T): T = t\n\n                val value5 = identity(\n                    1 to\n                            2 to // diktat:WRONG_INDENTATION[expectedIndent = 8]\n                            3) // diktat:WRONG_INDENTATION[expectedIndent = 8]\n                \"\"\",\n                extendedIndentAfterOperators = TRUE))\n        fun `case 13`() = Unit\n\n        @IndentationTest(\n            first = IndentedSourceCode(\n                \"\"\"\n                fun <T : Any> identity(t: T): T = t\n\n                val value6 =\n                    identity(1 to\n                        2 to // diktat:WRONG_INDENTATION[expectedIndent = 12]\n                        3) // diktat:WRONG_INDENTATION[expectedIndent = 12]\n                \"\"\",\n                extendedIndentAfterOperators = FALSE),\n            second = IndentedSourceCode(\n                \"\"\"\n                fun <T : Any> identity(t: T): T = t\n\n                val value6 =\n                    identity(1 to\n                            2 to // diktat:WRONG_INDENTATION[expectedIndent = 8]\n                            3) // diktat:WRONG_INDENTATION[expectedIndent = 8]\n                \"\"\",\n                extendedIndentAfterOperators = TRUE))\n        fun `case 14`() = Unit\n\n        @IndentationTest(\n            first = IndentedSourceCode(\n                \"\"\"\n                fun <T : Any> identity(t: T): T = t\n\n                /**\n                 * Line breaks:\n                 *\n                 * 1. before the expression body (`=`),\n                 * 2. before the effective function arguments, and\n                 * 3. on each infix function call ([to]).\n                 */\n                val value7 =\n                    identity(\n                        1 to\n                            2 to // diktat:WRONG_INDENTATION[expectedIndent = 16]\n                            3) // diktat:WRONG_INDENTATION[expectedIndent = 16]\n                \"\"\",\n                extendedIndentAfterOperators = FALSE),\n            second = IndentedSourceCode(\n                \"\"\"\n                fun <T : Any> identity(t: T): T = t\n\n                /**\n                 * Line breaks:\n                 *\n                 * 1. before the expression body (`=`),\n                 * 2. before the effective function arguments, and\n                 * 3. on each infix function call ([to]).\n                 */\n                val value7 =\n                    identity(\n                        1 to\n                                2 to // diktat:WRONG_INDENTATION[expectedIndent = 12]\n                                3) // diktat:WRONG_INDENTATION[expectedIndent = 12]\n                \"\"\",\n                extendedIndentAfterOperators = TRUE))\n        fun `case 15`() = Unit\n\n        @IndentationTest(\n            first = IndentedSourceCode(\n                \"\"\"\n                fun <T : Any> identity(t: T): T = t\n\n                val value8 = identity(identity(1 to\n                    2 to // diktat:WRONG_INDENTATION[expectedIndent = 8]\n                    3)) // diktat:WRONG_INDENTATION[expectedIndent = 8]\n                \"\"\",\n                extendedIndentAfterOperators = FALSE),\n            second = IndentedSourceCode(\n                \"\"\"\n                fun <T : Any> identity(t: T): T = t\n\n                val value8 = identity(identity(1 to\n                        2 to // diktat:WRONG_INDENTATION[expectedIndent = 4]\n                        3)) // diktat:WRONG_INDENTATION[expectedIndent = 4]\n                \"\"\",\n                extendedIndentAfterOperators = TRUE))\n        fun `case 16`() = Unit\n\n        @IndentationTest(\n            first = IndentedSourceCode(\n                \"\"\"\n                fun <T : Any> identity(t: T): T = t\n\n                val value9 = identity(identity(\n                    1 to\n                        2 to // diktat:WRONG_INDENTATION[expectedIndent = 12]\n                        3)) // diktat:WRONG_INDENTATION[expectedIndent = 12]\n                \"\"\",\n                extendedIndentAfterOperators = FALSE),\n            second = IndentedSourceCode(\n                \"\"\"\n                fun <T : Any> identity(t: T): T = t\n\n                val value9 = identity(identity(\n                    1 to\n                            2 to // diktat:WRONG_INDENTATION[expectedIndent = 8]\n                            3)) // diktat:WRONG_INDENTATION[expectedIndent = 8]\n                \"\"\",\n                extendedIndentAfterOperators = TRUE))\n        fun `case 17`() = Unit\n\n        @IndentationTest(\n            first = IndentedSourceCode(\n                \"\"\"\n                fun <T : Any> identity(t: T): T = t\n\n                val value10 =\n                    identity(identity(1 to\n                        2 to // diktat:WRONG_INDENTATION[expectedIndent = 12]\n                        3)) // diktat:WRONG_INDENTATION[expectedIndent = 12]\n                \"\"\",\n                extendedIndentAfterOperators = FALSE),\n            second = IndentedSourceCode(\n                \"\"\"\n                fun <T : Any> identity(t: T): T = t\n\n                val value10 =\n                    identity(identity(1 to\n                            2 to // diktat:WRONG_INDENTATION[expectedIndent = 8]\n                            3)) // diktat:WRONG_INDENTATION[expectedIndent = 8]\n                \"\"\",\n                extendedIndentAfterOperators = TRUE))\n        fun `case 18`() = Unit\n\n        @IndentationTest(\n            first = IndentedSourceCode(\n                \"\"\"\n                fun <T : Any> identity(t: T): T = t\n\n                val value11 =\n                    identity(identity(\n                        1 to\n                            2 to // diktat:WRONG_INDENTATION[expectedIndent = 16]\n                            3)) // diktat:WRONG_INDENTATION[expectedIndent = 16]\n                \"\"\",\n                extendedIndentAfterOperators = FALSE),\n            second = IndentedSourceCode(\n                \"\"\"\n                fun <T : Any> identity(t: T): T = t\n\n                val value11 =\n                    identity(identity(\n                        1 to\n                                2 to // diktat:WRONG_INDENTATION[expectedIndent = 12]\n                                3)) // diktat:WRONG_INDENTATION[expectedIndent = 12]\n                \"\"\",\n                extendedIndentAfterOperators = TRUE))\n        fun `case 19`() = Unit\n\n        @IndentationTest(\n            first = IndentedSourceCode(\n                \"\"\"\n                // Same as above, but using a custom getter instead of an explicit initializer.\n                val value12\n                    get() =\n                        1 to\n                            2 to // diktat:WRONG_INDENTATION[expectedIndent = 16]\n                            3 // diktat:WRONG_INDENTATION[expectedIndent = 16]\n                \"\"\",\n                extendedIndentAfterOperators = FALSE),\n            second = IndentedSourceCode(\n                \"\"\"\n                // Same as above, but using a custom getter instead of an explicit initializer.\n                val value12\n                    get() =\n                        1 to\n                                2 to // diktat:WRONG_INDENTATION[expectedIndent = 12]\n                                3 // diktat:WRONG_INDENTATION[expectedIndent = 12]\n                \"\"\",\n                extendedIndentAfterOperators = TRUE))\n        fun `case 20`() = Unit\n\n        @IndentationTest(\n            first = IndentedSourceCode(\n                \"\"\"\n                // Same as above, but using a custom getter instead of an explicit initializer.\n                val value13\n                    get() =\n                        (1 to\n                            2 to // diktat:WRONG_INDENTATION[expectedIndent = 16]\n                            3) // diktat:WRONG_INDENTATION[expectedIndent = 16]\n                \"\"\",\n                extendedIndentAfterOperators = FALSE),\n            second = IndentedSourceCode(\n                \"\"\"\n                // Same as above, but using a custom getter instead of an explicit initializer.\n                val value13\n                    get() =\n                        (1 to\n                                2 to // diktat:WRONG_INDENTATION[expectedIndent = 12]\n                                3) // diktat:WRONG_INDENTATION[expectedIndent = 12]\n                \"\"\",\n                extendedIndentAfterOperators = TRUE))\n        fun `case 21`() = Unit\n\n        @IndentationTest(\n            first = IndentedSourceCode(\n                \"\"\"\n                fun <T : Any> identity(t: T): T = t\n\n                // Same as above, but using a custom getter instead of an explicit initializer.\n                val value14\n                    get() =\n                        identity(1 to\n                            2 to // diktat:WRONG_INDENTATION[expectedIndent = 16]\n                            3) // diktat:WRONG_INDENTATION[expectedIndent = 16]\n                \"\"\",\n                extendedIndentAfterOperators = FALSE),\n            second = IndentedSourceCode(\n                \"\"\"\n                fun <T : Any> identity(t: T): T = t\n\n                // Same as above, but using a custom getter instead of an explicit initializer.\n                val value14\n                    get() =\n                        identity(1 to\n                                2 to // diktat:WRONG_INDENTATION[expectedIndent = 12]\n                                3) // diktat:WRONG_INDENTATION[expectedIndent = 12]\n                \"\"\",\n                extendedIndentAfterOperators = TRUE))\n        fun `case 22`() = Unit\n\n        @IndentationTest(\n            first = IndentedSourceCode(\n                \"\"\"\n                fun <T : Any> identity(t: T): T = t\n\n                // Same as above, but using a custom getter instead of an explicit initializer.\n                val value15\n                    get() =\n                        identity(identity(1 to\n                            2 to // diktat:WRONG_INDENTATION[expectedIndent = 16]\n                            3)) // diktat:WRONG_INDENTATION[expectedIndent = 16]\n                \"\"\",\n                extendedIndentAfterOperators = FALSE),\n            second = IndentedSourceCode(\n                \"\"\"\n                fun <T : Any> identity(t: T): T = t\n\n                // Same as above, but using a custom getter instead of an explicit initializer.\n                val value15\n                    get() =\n                        identity(identity(1 to\n                                2 to // diktat:WRONG_INDENTATION[expectedIndent = 12]\n                                3)) // diktat:WRONG_INDENTATION[expectedIndent = 12]\n                \"\"\",\n                extendedIndentAfterOperators = TRUE))\n        fun `case 23`() = Unit\n\n        @IndentationTest(\n            first = IndentedSourceCode(\n                \"\"\"\n                fun f() {\n                    g(42 as\n                        Integer) // diktat:WRONG_INDENTATION[expectedIndent = 12]\n                }\n                \"\"\",\n                extendedIndentAfterOperators = FALSE),\n            second = IndentedSourceCode(\n                \"\"\"\n                fun f() {\n                    g(42 as\n                            Integer) // diktat:WRONG_INDENTATION[expectedIndent = 8]\n                }\n                \"\"\",\n                extendedIndentAfterOperators = TRUE))\n        fun `case 24`() = Unit\n\n        @IndentationTest(\n            first = IndentedSourceCode(\n                \"\"\"\n                fun f() {\n                    g(\"\" as?\n                        String?) // diktat:WRONG_INDENTATION[expectedIndent = 12]\n                }\n                \"\"\",\n                extendedIndentAfterOperators = FALSE),\n            second = IndentedSourceCode(\n                \"\"\"\n                fun f() {\n                    g(\"\" as?\n                            String?) // diktat:WRONG_INDENTATION[expectedIndent = 8]\n                }\n                \"\"\",\n                extendedIndentAfterOperators = TRUE))\n        fun `case 25`() = Unit\n\n        @IndentationTest(\n            first = IndentedSourceCode(\n                \"\"\"\n                fun f() {\n                    // The dot-qualified expression is always single-indented.\n                    \"\"\n                        .length as\n                        Int // diktat:WRONG_INDENTATION[expectedIndent = 12]\n                }\n                \"\"\",\n                extendedIndentAfterOperators = FALSE),\n            second = IndentedSourceCode(\n                \"\"\"\n                fun f() {\n                    // The dot-qualified expression is always single-indented.\n                    \"\"\n                        .length as\n                            Int // diktat:WRONG_INDENTATION[expectedIndent = 8]\n                }\n                \"\"\",\n                extendedIndentAfterOperators = TRUE))\n        fun `case 26`() = Unit\n    }\n\n    /**\n     * Expressions wrapped before an operator or an infix function.\n     *\n     * See [#1340](https://github.com/saveourtool/diktat/issues/1340).\n     */\n    @Nested\n    @TestMethodOrder(NaturalDisplayName::class)\n    inner class `Expressions wrapped before operator` {\n        @IndentationTest(\n            first = IndentedSourceCode(\n                \"\"\"\n                fun f() {\n                    systemUiVisibility = (View.SYSTEM_UI_FLAG_LOW_PROFILE\n                        or View.SYSTEM_UI_FLAG_FULLSCREEN // diktat:WRONG_INDENTATION[expectedIndent = 12]\n                        or View.SYSTEM_UI_FLAG_LAYOUT_STABLE // diktat:WRONG_INDENTATION[expectedIndent = 12]\n                        or View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY // diktat:WRONG_INDENTATION[expectedIndent = 12]\n                        or View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION // diktat:WRONG_INDENTATION[expectedIndent = 12]\n                        or View.SYSTEM_UI_FLAG_HIDE_NAVIGATION) // diktat:WRONG_INDENTATION[expectedIndent = 12]\n                }\n                \"\"\",\n                extendedIndentAfterOperators = FALSE),\n            second = IndentedSourceCode(\n                \"\"\"\n                fun f() {\n                    systemUiVisibility = (View.SYSTEM_UI_FLAG_LOW_PROFILE\n                            or View.SYSTEM_UI_FLAG_FULLSCREEN // diktat:WRONG_INDENTATION[expectedIndent = 8]\n                            or View.SYSTEM_UI_FLAG_LAYOUT_STABLE // diktat:WRONG_INDENTATION[expectedIndent = 8]\n                            or View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY // diktat:WRONG_INDENTATION[expectedIndent = 8]\n                            or View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION // diktat:WRONG_INDENTATION[expectedIndent = 8]\n                            or View.SYSTEM_UI_FLAG_HIDE_NAVIGATION) // diktat:WRONG_INDENTATION[expectedIndent = 8]\n                }\n                \"\"\",\n                extendedIndentAfterOperators = TRUE))\n        fun `case 1`() = Unit\n\n        @IndentationTest(\n            first = IndentedSourceCode(\n                \"\"\"\n                val systemUiVisibility = (View.SYSTEM_UI_FLAG_LOW_PROFILE\n                    or View.SYSTEM_UI_FLAG_FULLSCREEN // diktat:WRONG_INDENTATION[expectedIndent = 8]\n                    or View.SYSTEM_UI_FLAG_LAYOUT_STABLE // diktat:WRONG_INDENTATION[expectedIndent = 8]\n                    or View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY // diktat:WRONG_INDENTATION[expectedIndent = 8]\n                    or View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION // diktat:WRONG_INDENTATION[expectedIndent = 8]\n                    or View.SYSTEM_UI_FLAG_HIDE_NAVIGATION) // diktat:WRONG_INDENTATION[expectedIndent = 8]\n                \"\"\",\n                extendedIndentAfterOperators = FALSE),\n            second = IndentedSourceCode(\n                \"\"\"\n                val systemUiVisibility = (View.SYSTEM_UI_FLAG_LOW_PROFILE\n                        or View.SYSTEM_UI_FLAG_FULLSCREEN // diktat:WRONG_INDENTATION[expectedIndent = 4]\n                        or View.SYSTEM_UI_FLAG_LAYOUT_STABLE // diktat:WRONG_INDENTATION[expectedIndent = 4]\n                        or View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY // diktat:WRONG_INDENTATION[expectedIndent = 4]\n                        or View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION // diktat:WRONG_INDENTATION[expectedIndent = 4]\n                        or View.SYSTEM_UI_FLAG_HIDE_NAVIGATION) // diktat:WRONG_INDENTATION[expectedIndent = 4]\n                \"\"\",\n                extendedIndentAfterOperators = TRUE))\n        fun `case 2`() = Unit\n\n        @IndentationTest(\n            first = IndentedSourceCode(\n                \"\"\"\n                const val FOO = 1\n\n                const val BAR = 2\n\n                const val BAZ = 4\n\n                fun acceptInteger(arg: Int) = Unit\n\n                fun main() {\n                    acceptInteger(FOO or BAR or BAZ or FOO or BAR or BAZ\n                        or FOO or BAR or BAZ or FOO or BAR or BAZ or FOO or BAR or BAZ // diktat:WRONG_INDENTATION[expectedIndent = 12]\n                        or FOO or BAR or BAZ) // diktat:WRONG_INDENTATION[expectedIndent = 12]\n                }\n                \"\"\",\n                extendedIndentAfterOperators = FALSE),\n            second = IndentedSourceCode(\n                \"\"\"\n                const val FOO = 1\n\n                const val BAR = 2\n\n                const val BAZ = 4\n\n                fun acceptInteger(arg: Int) = Unit\n\n                fun main() {\n                    acceptInteger(FOO or BAR or BAZ or FOO or BAR or BAZ\n                            or FOO or BAR or BAZ or FOO or BAR or BAZ or FOO or BAR or BAZ // diktat:WRONG_INDENTATION[expectedIndent = 8]\n                            or FOO or BAR or BAZ) // diktat:WRONG_INDENTATION[expectedIndent = 8]\n                }\n                \"\"\",\n                extendedIndentAfterOperators = TRUE))\n        fun `case 3`() = Unit\n\n        @IndentationTest(\n            first = IndentedSourceCode(\n                \"\"\"\n                const val TRUE = true\n\n                const val FALSE = false\n\n                fun acceptBoolean(arg: Boolean) = Unit\n\n                fun f() {\n                    acceptBoolean(TRUE\n                        || FALSE // diktat:WRONG_INDENTATION[expectedIndent = 12]\n                        || TRUE) // diktat:WRONG_INDENTATION[expectedIndent = 12]\n                }\n                \"\"\",\n                extendedIndentAfterOperators = FALSE),\n            second = IndentedSourceCode(\n                \"\"\"\n                const val TRUE = true\n\n                const val FALSE = false\n\n                fun acceptBoolean(arg: Boolean) = Unit\n\n                fun f() {\n                    acceptBoolean(TRUE\n                            || FALSE // diktat:WRONG_INDENTATION[expectedIndent = 8]\n                            || TRUE) // diktat:WRONG_INDENTATION[expectedIndent = 8]\n                }\n                \"\"\",\n                extendedIndentAfterOperators = TRUE))\n        fun `case 4`() = Unit\n\n        @IndentationTest(\n            first = IndentedSourceCode(\n                \"\"\"\n                val c = (3\n                    + 2) // diktat:WRONG_INDENTATION[expectedIndent = 8]\n                \"\"\",\n                extendedIndentAfterOperators = FALSE),\n            second = IndentedSourceCode(\n                \"\"\"\n                val c = (3\n                        + 2) // diktat:WRONG_INDENTATION[expectedIndent = 4]\n                \"\"\",\n                extendedIndentAfterOperators = TRUE))\n        fun `case 5`() = Unit\n\n        @IndentationTest(\n            first = IndentedSourceCode(\n                \"\"\"\n                infix fun Int.combineWith(that: Int) = this + that\n\n                fun f() {\n                    val x = (1\n                        combineWith 2 // diktat:WRONG_INDENTATION[expectedIndent = 12]\n                        combineWith 3 // diktat:WRONG_INDENTATION[expectedIndent = 12]\n                        combineWith 4 // diktat:WRONG_INDENTATION[expectedIndent = 12]\n                        combineWith 5 // diktat:WRONG_INDENTATION[expectedIndent = 12]\n                        combineWith 6) // diktat:WRONG_INDENTATION[expectedIndent = 12]\n                }\n                \"\"\",\n                extendedIndentAfterOperators = FALSE),\n            second = IndentedSourceCode(\n                \"\"\"\n                infix fun Int.combineWith(that: Int) = this + that\n\n                fun f() {\n                    val x = (1\n                            combineWith 2 // diktat:WRONG_INDENTATION[expectedIndent = 8]\n                            combineWith 3 // diktat:WRONG_INDENTATION[expectedIndent = 8]\n                            combineWith 4 // diktat:WRONG_INDENTATION[expectedIndent = 8]\n                            combineWith 5 // diktat:WRONG_INDENTATION[expectedIndent = 8]\n                            combineWith 6) // diktat:WRONG_INDENTATION[expectedIndent = 8]\n                }\n                \"\"\",\n                extendedIndentAfterOperators = TRUE))\n        fun `case 6`() = Unit\n\n        @IndentationTest(\n            first = IndentedSourceCode(\n                \"\"\"\n                fun f(i1: Int, i2: Int, i3: Int): Int {\n                    if (i2 > 0\n                        && i3 < 0) { // diktat:WRONG_INDENTATION[expectedIndent = 12]\n                        return 2\n                    }\n                    return 0\n                }\n                \"\"\",\n                extendedIndentAfterOperators = FALSE),\n            second = IndentedSourceCode(\n                \"\"\"\n                fun f(i1: Int, i2: Int, i3: Int): Int {\n                    if (i2 > 0\n                            && i3 < 0) { // diktat:WRONG_INDENTATION[expectedIndent = 8]\n                        return 2\n                    }\n                    return 0\n                }\n                \"\"\",\n                extendedIndentAfterOperators = TRUE))\n        fun `case 7`() = Unit\n\n        @IndentationTest(\n            first = IndentedSourceCode(\n                \"\"\"\n                val value1 = (1\n                    to 2 // diktat:WRONG_INDENTATION[expectedIndent = 8]\n                    to 3) // diktat:WRONG_INDENTATION[expectedIndent = 8]\n                \"\"\",\n                extendedIndentAfterOperators = FALSE),\n            second = IndentedSourceCode(\n                \"\"\"\n                val value1 = (1\n                        to 2 // diktat:WRONG_INDENTATION[expectedIndent = 4]\n                        to 3) // diktat:WRONG_INDENTATION[expectedIndent = 4]\n                \"\"\",\n                extendedIndentAfterOperators = TRUE))\n        fun `case 8`() = Unit\n\n        @IndentationTest(\n            first = IndentedSourceCode(\n                \"\"\"\n                val value2 =\n                    (1\n                        to 2 // diktat:WRONG_INDENTATION[expectedIndent = 12]\n                        to 3) // diktat:WRONG_INDENTATION[expectedIndent = 12]\n                \"\"\",\n                extendedIndentAfterOperators = FALSE),\n            second = IndentedSourceCode(\n                \"\"\"\n                val value2 =\n                    (1\n                            to 2 // diktat:WRONG_INDENTATION[expectedIndent = 8]\n                            to 3) // diktat:WRONG_INDENTATION[expectedIndent = 8]\n                \"\"\",\n                extendedIndentAfterOperators = TRUE))\n        fun `case 9`() = Unit\n\n        @IndentationTest(\n            first = IndentedSourceCode(\n                \"\"\"\n                fun <T : Any> identity(t: T): T = t\n\n                val value3 = identity(1\n                    to 2 // diktat:WRONG_INDENTATION[expectedIndent = 8]\n                    to 3) // diktat:WRONG_INDENTATION[expectedIndent = 8]\n                \"\"\",\n                extendedIndentAfterOperators = FALSE),\n            second = IndentedSourceCode(\n                \"\"\"\n                fun <T : Any> identity(t: T): T = t\n\n                val value3 = identity(1\n                        to 2 // diktat:WRONG_INDENTATION[expectedIndent = 4]\n                        to 3) // diktat:WRONG_INDENTATION[expectedIndent = 4]\n                \"\"\",\n                extendedIndentAfterOperators = TRUE))\n        fun `case 10`() = Unit\n\n        @IndentationTest(\n            first = IndentedSourceCode(\n                \"\"\"\n                fun <T : Any> identity(t: T): T = t\n\n                val value4 = identity(\n                    1\n                        to 2 // diktat:WRONG_INDENTATION[expectedIndent = 12]\n                        to 3) // diktat:WRONG_INDENTATION[expectedIndent = 12]\n                \"\"\",\n                extendedIndentAfterOperators = FALSE),\n            second = IndentedSourceCode(\n                \"\"\"\n                fun <T : Any> identity(t: T): T = t\n\n                val value4 = identity(\n                    1\n                            to 2 // diktat:WRONG_INDENTATION[expectedIndent = 8]\n                            to 3) // diktat:WRONG_INDENTATION[expectedIndent = 8]\n                \"\"\",\n                extendedIndentAfterOperators = TRUE))\n        fun `case 11`() = Unit\n\n        @IndentationTest(\n            first = IndentedSourceCode(\n                \"\"\"\n                fun <T : Any> identity(t: T): T = t\n\n                val value5 =\n                    identity(1\n                        to 2 // diktat:WRONG_INDENTATION[expectedIndent = 12]\n                        to 3) // diktat:WRONG_INDENTATION[expectedIndent = 12]\n                \"\"\",\n                extendedIndentAfterOperators = FALSE),\n            second = IndentedSourceCode(\n                \"\"\"\n                fun <T : Any> identity(t: T): T = t\n\n                val value5 =\n                    identity(1\n                            to 2 // diktat:WRONG_INDENTATION[expectedIndent = 8]\n                            to 3) // diktat:WRONG_INDENTATION[expectedIndent = 8]\n                \"\"\",\n                extendedIndentAfterOperators = TRUE))\n        fun `case 12`() = Unit\n\n        @IndentationTest(\n            first = IndentedSourceCode(\n                \"\"\"\n                fun <T : Any> identity(t: T): T = t\n\n                /**\n                 * Line breaks:\n                 *\n                 * 1. before the expression body (`=`),\n                 * 2. before the effective function arguments, and\n                 * 3. on each infix function call ([to]).\n                 */\n                val value6 =\n                    identity(\n                        1\n                            to 2 // diktat:WRONG_INDENTATION[expectedIndent = 16]\n                            to 3) // diktat:WRONG_INDENTATION[expectedIndent = 16]\n                \"\"\",\n                extendedIndentAfterOperators = FALSE),\n            second = IndentedSourceCode(\n                \"\"\"\n                fun <T : Any> identity(t: T): T = t\n\n                /**\n                 * Line breaks:\n                 *\n                 * 1. before the expression body (`=`),\n                 * 2. before the effective function arguments, and\n                 * 3. on each infix function call ([to]).\n                 */\n                val value6 =\n                    identity(\n                        1\n                                to 2 // diktat:WRONG_INDENTATION[expectedIndent = 12]\n                                to 3) // diktat:WRONG_INDENTATION[expectedIndent = 12]\n                \"\"\",\n                extendedIndentAfterOperators = TRUE))\n        fun `case 13`() = Unit\n\n        @IndentationTest(\n            first = IndentedSourceCode(\n                \"\"\"\n                fun <T : Any> identity(t: T): T = t\n\n                val value7 = identity(identity(1\n                    to 2 // diktat:WRONG_INDENTATION[expectedIndent = 8]\n                    to 3)) // diktat:WRONG_INDENTATION[expectedIndent = 8]\n                \"\"\",\n                extendedIndentAfterOperators = FALSE),\n            second = IndentedSourceCode(\n                \"\"\"\n                fun <T : Any> identity(t: T): T = t\n\n                val value7 = identity(identity(1\n                        to 2 // diktat:WRONG_INDENTATION[expectedIndent = 4]\n                        to 3)) // diktat:WRONG_INDENTATION[expectedIndent = 4]\n                \"\"\",\n                extendedIndentAfterOperators = TRUE))\n        fun `case 14`() = Unit\n\n        @IndentationTest(\n            first = IndentedSourceCode(\n                \"\"\"\n                fun <T : Any> identity(t: T): T = t\n\n                val value8 = identity(identity(\n                    1\n                        to 2 // diktat:WRONG_INDENTATION[expectedIndent = 12]\n                        to 3)) // diktat:WRONG_INDENTATION[expectedIndent = 12]\n                \"\"\",\n                extendedIndentAfterOperators = FALSE),\n            second = IndentedSourceCode(\n                \"\"\"\n                fun <T : Any> identity(t: T): T = t\n\n                val value8 = identity(identity(\n                    1\n                            to 2 // diktat:WRONG_INDENTATION[expectedIndent = 8]\n                            to 3)) // diktat:WRONG_INDENTATION[expectedIndent = 8]\n                \"\"\",\n                extendedIndentAfterOperators = TRUE))\n        fun `case 15`() = Unit\n\n        @IndentationTest(\n            first = IndentedSourceCode(\n                \"\"\"\n                fun <T : Any> identity(t: T): T = t\n\n                val value9 =\n                    identity(identity(1\n                        to 2 // diktat:WRONG_INDENTATION[expectedIndent = 12]\n                        to 3)) // diktat:WRONG_INDENTATION[expectedIndent = 12]\n                \"\"\",\n                extendedIndentAfterOperators = FALSE),\n            second = IndentedSourceCode(\n                \"\"\"\n                fun <T : Any> identity(t: T): T = t\n\n                val value9 =\n                    identity(identity(1\n                            to 2 // diktat:WRONG_INDENTATION[expectedIndent = 8]\n                            to 3)) // diktat:WRONG_INDENTATION[expectedIndent = 8]\n                \"\"\",\n                extendedIndentAfterOperators = TRUE))\n        fun `case 16`() = Unit\n\n        @IndentationTest(\n            first = IndentedSourceCode(\n                \"\"\"\n                fun <T : Any> identity(t: T): T = t\n\n                val value10 =\n                    identity(identity(\n                        1\n                            to 2 // diktat:WRONG_INDENTATION[expectedIndent = 16]\n                            to 3)) // diktat:WRONG_INDENTATION[expectedIndent = 16]\n                \"\"\",\n                extendedIndentAfterOperators = FALSE),\n            second = IndentedSourceCode(\n                \"\"\"\n                fun <T : Any> identity(t: T): T = t\n\n                val value10 =\n                    identity(identity(\n                        1\n                                to 2 // diktat:WRONG_INDENTATION[expectedIndent = 12]\n                                to 3)) // diktat:WRONG_INDENTATION[expectedIndent = 12]\n                \"\"\",\n                extendedIndentAfterOperators = TRUE))\n        fun `case 17`() = Unit\n\n        @IndentationTest(\n            first = IndentedSourceCode(\n                \"\"\"\n                // Same as above, but using a custom getter instead of an explicit initializer.\n                val value11\n                    get() =\n                        (1\n                            to 2 // diktat:WRONG_INDENTATION[expectedIndent = 16]\n                            to 3) // diktat:WRONG_INDENTATION[expectedIndent = 16]\n                \"\"\",\n                extendedIndentAfterOperators = FALSE),\n            second = IndentedSourceCode(\n                \"\"\"\n                // Same as above, but using a custom getter instead of an explicit initializer.\n                val value11\n                    get() =\n                        (1\n                                to 2 // diktat:WRONG_INDENTATION[expectedIndent = 12]\n                                to 3) // diktat:WRONG_INDENTATION[expectedIndent = 12]\n                \"\"\",\n                extendedIndentAfterOperators = TRUE))\n        fun `case 18`() = Unit\n\n        @IndentationTest(\n            first = IndentedSourceCode(\n                \"\"\"\n                fun <T : Any> identity(t: T): T = t\n\n                // Same as above, but using a custom getter instead of an explicit initializer.\n                val value12\n                    get() =\n                        identity(1\n                            to 2 // diktat:WRONG_INDENTATION[expectedIndent = 16]\n                            to 3) // diktat:WRONG_INDENTATION[expectedIndent = 16]\n                \"\"\",\n                extendedIndentAfterOperators = FALSE),\n            second = IndentedSourceCode(\n                \"\"\"\n                fun <T : Any> identity(t: T): T = t\n\n                // Same as above, but using a custom getter instead of an explicit initializer.\n                val value12\n                    get() =\n                        identity(1\n                                to 2 // diktat:WRONG_INDENTATION[expectedIndent = 12]\n                                to 3) // diktat:WRONG_INDENTATION[expectedIndent = 12]\n                \"\"\",\n                extendedIndentAfterOperators = TRUE))\n        fun `case 19`() = Unit\n\n        @IndentationTest(\n            first = IndentedSourceCode(\n                \"\"\"\n                fun <T : Any> identity(t: T): T = t\n\n                // Same as above, but using a custom getter instead of an explicit initializer.\n                val value13\n                    get() =\n                        identity(identity(1\n                            to 2 // diktat:WRONG_INDENTATION[expectedIndent = 16]\n                            to 3)) // diktat:WRONG_INDENTATION[expectedIndent = 16]\n                \"\"\",\n                extendedIndentAfterOperators = FALSE),\n            second = IndentedSourceCode(\n                \"\"\"\n                fun <T : Any> identity(t: T): T = t\n\n                // Same as above, but using a custom getter instead of an explicit initializer.\n                val value13\n                    get() =\n                        identity(identity(1\n                                to 2 // diktat:WRONG_INDENTATION[expectedIndent = 12]\n                                to 3)) // diktat:WRONG_INDENTATION[expectedIndent = 12]\n                \"\"\",\n                extendedIndentAfterOperators = TRUE))\n        fun `case 20`() = Unit\n\n        @IndentationTest(\n            first = IndentedSourceCode(\n                \"\"\"\n                fun f() {\n                    g(42\n                        as Integer) // diktat:WRONG_INDENTATION[expectedIndent = 12]\n                }\n                \"\"\",\n                extendedIndentAfterOperators = FALSE),\n            second = IndentedSourceCode(\n                \"\"\"\n                fun f() {\n                    g(42\n                            as Integer) // diktat:WRONG_INDENTATION[expectedIndent = 8]\n                }\n                \"\"\",\n                extendedIndentAfterOperators = TRUE))\n        fun `case 21`() = Unit\n\n        @IndentationTest(\n            first = IndentedSourceCode(\n                \"\"\"\n                fun f() {\n                    g(\"\"\n                        as? String?) // diktat:WRONG_INDENTATION[expectedIndent = 12]\n                }\n                \"\"\",\n                extendedIndentAfterOperators = FALSE),\n            second = IndentedSourceCode(\n                \"\"\"\n                fun f() {\n                    g(\"\"\n                            as? String?) // diktat:WRONG_INDENTATION[expectedIndent = 8]\n                }\n                \"\"\",\n                extendedIndentAfterOperators = TRUE))\n        fun `case 22`() = Unit\n\n        @IndentationTest(\n            first = IndentedSourceCode(\n                \"\"\"\n                fun f() {\n                    // The dot-qualified expression is always single-indented.\n                    \"\"\n                        .length\n                        as Int // diktat:WRONG_INDENTATION[expectedIndent = 12]\n                }\n                \"\"\",\n                extendedIndentAfterOperators = FALSE),\n            second = IndentedSourceCode(\n                \"\"\"\n                fun f() {\n                    // The dot-qualified expression is always single-indented.\n                    \"\"\n                        .length\n                            as Int // diktat:WRONG_INDENTATION[expectedIndent = 8]\n                }\n                \"\"\",\n                extendedIndentAfterOperators = TRUE))\n        fun `case 23`() = Unit\n    }\n\n    /**\n     * Parenthesized expressions.\n     *\n     * See [#1409](https://github.com/saveourtool/diktat/issues/1409).\n     */\n    @Nested\n    @TestMethodOrder(NaturalDisplayName::class)\n    inner class `Parentheses-surrounded infix expressions` {\n        @IndentationTest(\n            first = IndentedSourceCode(\n                \"\"\"\n                fun f1() = (\n                        1 + 2 // diktat:WRONG_INDENTATION[expectedIndent = 4]\n                )\n                \"\"\",\n                extendedIndentForExpressionBodies = FALSE,\n                extendedIndentAfterOperators = TRUE),\n            second = IndentedSourceCode(\n                \"\"\"\n                fun f1() = (\n                    1 + 2 // diktat:WRONG_INDENTATION[expectedIndent = 8]\n                )\n                \"\"\",\n                extendedIndentForExpressionBodies = TRUE,\n                extendedIndentAfterOperators = FALSE))\n        fun `case 1`() = Unit\n\n        @IndentationTest(\n            first = IndentedSourceCode(\n                \"\"\"\n                fun f2() = (\n                        1 + 2) // diktat:WRONG_INDENTATION[expectedIndent = 4]\n                \"\"\",\n                extendedIndentForExpressionBodies = FALSE,\n                extendedIndentAfterOperators = TRUE),\n            second = IndentedSourceCode(\n                \"\"\"\n                fun f2() = (\n                    1 + 2) // diktat:WRONG_INDENTATION[expectedIndent = 8]\n                \"\"\",\n                extendedIndentForExpressionBodies = TRUE,\n                extendedIndentAfterOperators = FALSE))\n        fun `case 2`() = Unit\n\n        @IndentationTest(\n            first = IndentedSourceCode(\n                \"\"\"\n                fun f3() =\n                    ( // diktat:WRONG_INDENTATION[expectedIndent = 8]\n                            1 + 2\n                    ) // diktat:WRONG_INDENTATION[expectedIndent = 8]\n                \"\"\",\n                extendedIndentForExpressionBodies = FALSE,\n                extendedIndentAfterOperators = TRUE),\n            second = IndentedSourceCode(\n                \"\"\"\n                fun f3() =\n                        ( // diktat:WRONG_INDENTATION[expectedIndent = 4]\n                            1 + 2\n                        ) // diktat:WRONG_INDENTATION[expectedIndent = 4]\n                \"\"\",\n                extendedIndentForExpressionBodies = TRUE,\n                extendedIndentAfterOperators = FALSE))\n        fun `case 3`() = Unit\n\n        @IndentationTest(\n            first = IndentedSourceCode(\n                \"\"\"\n                fun f4() =\n                    ( // diktat:WRONG_INDENTATION[expectedIndent = 8]\n                            1 + 2)\n                \"\"\",\n                extendedIndentForExpressionBodies = FALSE,\n                extendedIndentAfterOperators = TRUE),\n            second = IndentedSourceCode(\n                \"\"\"\n                fun f4() =\n                        ( // diktat:WRONG_INDENTATION[expectedIndent = 4]\n                            1 + 2)\n                \"\"\",\n                extendedIndentForExpressionBodies = TRUE,\n                extendedIndentAfterOperators = FALSE))\n        fun `case 4`() = Unit\n\n        @IndentationTest(\n            first = IndentedSourceCode(\n                \"\"\"\n                const val v1 = (\n                        1 + 2 // diktat:WRONG_INDENTATION[expectedIndent = 4]\n                )\n                \"\"\",\n                extendedIndentForExpressionBodies = FALSE,\n                extendedIndentAfterOperators = TRUE),\n            second = IndentedSourceCode(\n                \"\"\"\n                const val v1 = (\n                    1 + 2 // diktat:WRONG_INDENTATION[expectedIndent = 8]\n                )\n                \"\"\",\n                extendedIndentForExpressionBodies = TRUE,\n                extendedIndentAfterOperators = FALSE))\n        fun `case 5`() = Unit\n\n        @IndentationTest(\n            first = IndentedSourceCode(\n                \"\"\"\n                const val v2 = (\n                        1 + 2) // diktat:WRONG_INDENTATION[expectedIndent = 4]\n                \"\"\",\n                extendedIndentForExpressionBodies = FALSE,\n                extendedIndentAfterOperators = TRUE),\n            second = IndentedSourceCode(\n                \"\"\"\n                const val v2 = (\n                    1 + 2) // diktat:WRONG_INDENTATION[expectedIndent = 8]\n                \"\"\",\n                extendedIndentForExpressionBodies = TRUE,\n                extendedIndentAfterOperators = FALSE))\n        fun `case 6`() = Unit\n\n        @IndentationTest(\n            first = IndentedSourceCode(\n                \"\"\"\n                const val v3 =\n                    ( // diktat:WRONG_INDENTATION[expectedIndent = 8]\n                            1 + 2\n                    ) // diktat:WRONG_INDENTATION[expectedIndent = 8]\n                \"\"\",\n                extendedIndentForExpressionBodies = FALSE,\n                extendedIndentAfterOperators = TRUE),\n            second = IndentedSourceCode(\n                \"\"\"\n                const val v3 =\n                        ( // diktat:WRONG_INDENTATION[expectedIndent = 4]\n                            1 + 2\n                        ) // diktat:WRONG_INDENTATION[expectedIndent = 4]\n                \"\"\",\n                extendedIndentForExpressionBodies = TRUE,\n                extendedIndentAfterOperators = FALSE))\n        fun `case 7`() = Unit\n\n        @IndentationTest(\n            first = IndentedSourceCode(\n                \"\"\"\n                const val v4 =\n                    ( // diktat:WRONG_INDENTATION[expectedIndent = 8]\n                            1 + 2)\n                \"\"\",\n                extendedIndentForExpressionBodies = FALSE,\n                extendedIndentAfterOperators = TRUE),\n            second = IndentedSourceCode(\n                \"\"\"\n                const val v4 =\n                        ( // diktat:WRONG_INDENTATION[expectedIndent = 4]\n                            1 + 2)\n                \"\"\",\n                extendedIndentForExpressionBodies = TRUE,\n                extendedIndentAfterOperators = FALSE))\n        fun `case 8`() = Unit\n    }\n\n    /**\n     * Dot-qualified and safe-access expressions.\n     *\n     * See [#1336](https://github.com/saveourtool/diktat/issues/1336).\n     */\n    @Nested\n    @TestMethodOrder(NaturalDisplayName::class)\n    inner class `Dot- and safe-qualified expressions` {\n        @IndentationTest(\n            first = IndentedSourceCode(\n                \"\"\"\n                fun LocalDateTime.updateTime(\n                    hour: Int? = null,\n                    minute: Int? = null,\n                    second: Int? = null,\n                ): LocalDateTime = withHour(hour ?: getHour())\n                    .withMinute(minute ?: getMinute()) // diktat:WRONG_INDENTATION[expectedIndent = 8]\n                    .withSecond(second ?: getSecond()) // diktat:WRONG_INDENTATION[expectedIndent = 8]\n                \"\"\",\n                extendedIndentBeforeDot = FALSE),\n            second = IndentedSourceCode(\n                \"\"\"\n                fun LocalDateTime.updateTime(\n                    hour: Int? = null,\n                    minute: Int? = null,\n                    second: Int? = null,\n                ): LocalDateTime = withHour(hour ?: getHour())\n                        .withMinute(minute ?: getMinute()) // diktat:WRONG_INDENTATION[expectedIndent = 4]\n                        .withSecond(second ?: getSecond()) // diktat:WRONG_INDENTATION[expectedIndent = 4]\n                \"\"\",\n                extendedIndentBeforeDot = TRUE))\n        fun `case 1`() = Unit\n\n        @IndentationTest(\n            first = IndentedSourceCode(\n                \"\"\"\n                fun f() {\n                    first()\n                        .second() // diktat:WRONG_INDENTATION[expectedIndent = 12]\n                        .third() // diktat:WRONG_INDENTATION[expectedIndent = 12]\n                }\n                \"\"\",\n                extendedIndentBeforeDot = FALSE),\n            second = IndentedSourceCode(\n                \"\"\"\n                fun f() {\n                    first()\n                            .second() // diktat:WRONG_INDENTATION[expectedIndent = 8]\n                            .third() // diktat:WRONG_INDENTATION[expectedIndent = 8]\n                }\n                \"\"\",\n                extendedIndentBeforeDot = TRUE))\n        fun `case 2`() = Unit\n\n        @IndentationTest(\n            first = IndentedSourceCode(\n                \"\"\"\n                val a = first()\n                    .second() // diktat:WRONG_INDENTATION[expectedIndent = 8]\n                    .third() // diktat:WRONG_INDENTATION[expectedIndent = 8]\n                \"\"\",\n                extendedIndentBeforeDot = FALSE),\n            second = IndentedSourceCode(\n                \"\"\"\n                val a = first()\n                        .second() // diktat:WRONG_INDENTATION[expectedIndent = 4]\n                        .third() // diktat:WRONG_INDENTATION[expectedIndent = 4]\n                \"\"\",\n                extendedIndentBeforeDot = TRUE))\n        fun `case 3`() = Unit\n\n        @IndentationTest(\n            first = IndentedSourceCode(\n                \"\"\"\n                val b = first()\n                    ?.second() // diktat:WRONG_INDENTATION[expectedIndent = 8]\n                    ?.third() // diktat:WRONG_INDENTATION[expectedIndent = 8]\n                \"\"\",\n                extendedIndentBeforeDot = FALSE),\n            second = IndentedSourceCode(\n                \"\"\"\n                val b = first()\n                        ?.second() // diktat:WRONG_INDENTATION[expectedIndent = 4]\n                        ?.third() // diktat:WRONG_INDENTATION[expectedIndent = 4]\n                \"\"\",\n                extendedIndentBeforeDot = TRUE))\n        fun `case 4`() = Unit\n\n        @IndentationTest(\n            first = IndentedSourceCode(\n                \"\"\"\n                fun f1() = first()\n                    .second() // diktat:WRONG_INDENTATION[expectedIndent = 8]\n                    .third() // diktat:WRONG_INDENTATION[expectedIndent = 8]\n                \"\"\",\n                extendedIndentBeforeDot = FALSE),\n            second = IndentedSourceCode(\n                \"\"\"\n                fun f1() = first()\n                        .second() // diktat:WRONG_INDENTATION[expectedIndent = 4]\n                        .third() // diktat:WRONG_INDENTATION[expectedIndent = 4]\n                \"\"\",\n                extendedIndentBeforeDot = TRUE))\n        fun `case 5`() = Unit\n\n        @IndentationTest(\n            first = IndentedSourceCode(\n                \"\"\"\n                fun f2() =\n                    first()\n                        .second() // diktat:WRONG_INDENTATION[expectedIndent = 12]\n                        .third() // diktat:WRONG_INDENTATION[expectedIndent = 12]\n                \"\"\",\n                extendedIndentBeforeDot = FALSE),\n            second = IndentedSourceCode(\n                \"\"\"\n                fun f2() =\n                    first()\n                            .second() // diktat:WRONG_INDENTATION[expectedIndent = 8]\n                            .third() // diktat:WRONG_INDENTATION[expectedIndent = 8]\n                \"\"\",\n                extendedIndentBeforeDot = TRUE))\n        fun `case 6`() = Unit\n\n        @IndentationTest(\n            first = IndentedSourceCode(\n                \"\"\"\n                fun f3() = g(first()\n                    .second() // diktat:WRONG_INDENTATION[expectedIndent = 8]\n                    .third() // diktat:WRONG_INDENTATION[expectedIndent = 8]\n                    .fourth()) // diktat:WRONG_INDENTATION[expectedIndent = 8]\n                \"\"\",\n                extendedIndentBeforeDot = FALSE),\n            second = IndentedSourceCode(\n                \"\"\"\n                fun f3() = g(first()\n                        .second() // diktat:WRONG_INDENTATION[expectedIndent = 4]\n                        .third() // diktat:WRONG_INDENTATION[expectedIndent = 4]\n                        .fourth()) // diktat:WRONG_INDENTATION[expectedIndent = 4]\n                \"\"\",\n                extendedIndentBeforeDot = TRUE))\n        fun `case 7`() = Unit\n\n        @IndentationTest(\n            first = IndentedSourceCode(\n                \"\"\"\n                fun f4() = g(\n                    first()\n                        .second() // diktat:WRONG_INDENTATION[expectedIndent = 12]\n                        .third() // diktat:WRONG_INDENTATION[expectedIndent = 12]\n                        .fourth()) // diktat:WRONG_INDENTATION[expectedIndent = 12]\n                \"\"\",\n                extendedIndentBeforeDot = FALSE),\n            second = IndentedSourceCode(\n                \"\"\"\n                fun f4() = g(\n                    first()\n                            .second() // diktat:WRONG_INDENTATION[expectedIndent = 8]\n                            .third() // diktat:WRONG_INDENTATION[expectedIndent = 8]\n                            .fourth()) // diktat:WRONG_INDENTATION[expectedIndent = 8]\n                \"\"\",\n                extendedIndentBeforeDot = TRUE))\n        fun `case 8`() = Unit\n    }\n\n    @Nested\n    @TestMethodOrder(NaturalDisplayName::class)\n    inner class `If expressions` {\n        /**\n         * #1351, case 1.\n         *\n         * Boolean operator priority (`&&` has higher priority than `||`).\n         *\n         * Currently, this is an incorrectly formatted code kept to detect the\n         * contract breakage. It will be re-formatted once the issue is fixed.\n         */\n        @IndentationTest(\n            first = IndentedSourceCode(\n                \"\"\"\n                fun f1() {\n                    if (valueParameterNode.parents().none { it.elementType == PRIMARY_CONSTRUCTOR } ||\n                        !valueParameterNode.hasChildOfType(VAL_KEYWORD) &&  // diktat:WRONG_INDENTATION[expectedIndent = 12]\n                            !valueParameterNode.hasChildOfType(VAR_KEYWORD) // diktat:WRONG_INDENTATION[expectedIndent = 16]\n                    ) {\n                        return\n                    }\n                }\n                \"\"\",\n                extendedIndentAfterOperators = FALSE),\n            second = IndentedSourceCode(\n                \"\"\"\n                fun f1() {\n                    if (valueParameterNode.parents().none { it.elementType == PRIMARY_CONSTRUCTOR } ||\n                            !valueParameterNode.hasChildOfType(VAL_KEYWORD) &&      // diktat:WRONG_INDENTATION[expectedIndent =  8]\n                                    !valueParameterNode.hasChildOfType(VAR_KEYWORD) // diktat:WRONG_INDENTATION[expectedIndent = 16]\n                    ) {\n                        return\n                    }\n                }\n                \"\"\",\n                extendedIndentAfterOperators = TRUE))\n        fun `case 1`() = Unit\n\n        /**\n         * #1351, case 2.\n         *\n         * IDEA combines the values of `CONTINUATION_INDENT_IN_IF_CONDITIONS`\n         * and `CONTINUATION_INDENT_FOR_CHAINED_CALLS`, so the resulting indent\n         * can be anything between 8 (2x) and 16 (4x).\n         *\n         * Currently, this is an incorrectly formatted code kept to detect the\n         * contract breakage. It will be re-formatted once the issue is fixed.\n         */\n        @IndentationTest(\n            first = IndentedSourceCode(\n                \"\"\"\n                fun f2() {\n                    val prevComment = if (valueParameterNode.siblings(forward = false)\n                        .takeWhile { it.elementType != EOL_COMMENT && it.elementType != BLOCK_COMMENT } // diktat:WRONG_INDENTATION[expectedIndent = 12]\n                        .all { it.elementType == WHITE_SPACE }                                          // diktat:WRONG_INDENTATION[expectedIndent = 12]\n                    ) {\n                        0\n                    } else {\n                        1\n                    }\n                }\n                \"\"\",\n                extendedIndentBeforeDot = FALSE),\n            second = IndentedSourceCode(\n                \"\"\"\n                fun f2() {\n                    val prevComment = if (valueParameterNode.siblings(forward = false)\n                            .takeWhile { it.elementType != EOL_COMMENT && it.elementType != BLOCK_COMMENT } // diktat:WRONG_INDENTATION[expectedIndent = 8]\n                            .all { it.elementType == WHITE_SPACE }                                          // diktat:WRONG_INDENTATION[expectedIndent = 8]\n                    ) {\n                        0\n                    } else {\n                        1\n                    }\n                }\n                \"\"\",\n                extendedIndentBeforeDot = TRUE))\n        fun `case 2`() = Unit\n    }\n\n    @Nested\n    @TestMethodOrder(NaturalDisplayName::class)\n    inner class `Comments inside binary expressions` {\n        @IndentationTest(\n            IndentedSourceCode(\n                \"\"\"\n                val x: Int = functionCall()\n                    // This is a comment\n                    ?: 42\n                \"\"\"),\n            singleConfiguration = true)\n        fun `case 1`() = Unit\n\n        @IndentationTest(\n            IndentedSourceCode(\n                \"\"\"\n                val x: Int = functionCall() as Int?\n                    // This is a comment\n                    ?: 42\n                \"\"\"),\n            singleConfiguration = true)\n        fun `case 2`() = Unit\n\n        @IndentationTest(\n            IndentedSourceCode(\n                \"\"\"\n                val x: Int = null as Int?\n                    // This is a comment\n                    ?: 42\n                \"\"\"),\n            singleConfiguration = true)\n        fun `case 3`() = Unit\n\n        @IndentationTest(\n            IndentedSourceCode(\n                \"\"\"\n                val x: Int = 42 as Int?\n                    // This is a comment\n                    ?: 42\n                \"\"\"),\n            singleConfiguration = true)\n        fun `case 4`() = Unit\n\n        @IndentationTest(\n            IndentedSourceCode(\n                \"\"\"\n                val x: Boolean = functionCall()\n                    /*\n                     * This is a block comment\n                     */\n                    ?: true\n                \"\"\"),\n            singleConfiguration = true)\n        fun `case 5`() = Unit\n\n        @IndentationTest(\n            IndentedSourceCode(\n                \"\"\"\n                val x: Boolean = functionCall() as Boolean?\n                    /*\n                     * This is a block comment\n                     */\n                    ?: true\n                \"\"\"),\n            singleConfiguration = true)\n        fun `case 6`() = Unit\n\n        @IndentationTest(\n            IndentedSourceCode(\n                \"\"\"\n                val x: Boolean = null as Boolean?\n                    /*\n                     * This is a block comment\n                     */\n                    ?: true\n                \"\"\"),\n            singleConfiguration = true)\n        fun `case 7`() = Unit\n\n        @IndentationTest(\n            IndentedSourceCode(\n                \"\"\"\n                val x: Boolean = true as Boolean?\n                    /*\n                     * This is a block comment\n                     */\n                    ?: true\n                \"\"\"),\n            singleConfiguration = true)\n        fun `case 8`() = Unit\n\n        @IndentationTest(\n            IndentedSourceCode(\n                \"\"\"\n                fun f(): String {\n                    return functionCall()\n                        // This is a comment\n                        // This is the 2nd line of the comment\n                        ?: \"default value\"\n                }\n                \"\"\"),\n            singleConfiguration = true)\n        fun `case 9`() = Unit\n\n        @IndentationTest(\n            IndentedSourceCode(\n                \"\"\"\n                fun f(): String {\n                    return functionCall() as String?\n                        // This is a comment\n                        // This is the 2nd line of the comment\n                        ?: \"default value\"\n                }\n                \"\"\"),\n            singleConfiguration = true)\n        fun `case 10`() = Unit\n\n        @IndentationTest(\n            IndentedSourceCode(\n                \"\"\"\n                fun f(): String {\n                    return null as String?\n                        // This is a comment\n                        // This is the 2nd line of the comment\n                        ?: \"default value\"\n                }\n                \"\"\"),\n            singleConfiguration = true)\n        fun `case 11`() = Unit\n\n        @IndentationTest(\n            IndentedSourceCode(\n                \"\"\"\n                fun f(): String {\n                    return \"return value\" as String?\n                        // This is a comment\n                        // This is the 2nd line of the comment\n                        ?: \"default value\"\n                        // This is a comment\n                        // This is the 2nd line of the comment\n                        ?: \"unreachable code\"\n                }\n                \"\"\"),\n            singleConfiguration = true)\n        fun `case 12`() = Unit\n    }\n\n    @Nested\n    @TestMethodOrder(NaturalDisplayName::class)\n    inner class `Multi-line Elvis expressions` {\n        @IndentationTest(\n            IndentedSourceCode(\n                \"\"\"\n                val elvisExpressionInsideBinaryExpressionA = true &&\n                        \"\"\n                            ?.trim()\n                            ?.trim()\n                            ?.trim()\n                            ?.isEmpty()\n                        ?: true\n                \"\"\"),\n            singleConfiguration = true)\n        fun `case 1`() = Unit\n\n        @IndentationTest(\n            IndentedSourceCode(\n                \"\"\"\n                val elvisExpressionInsideBinaryExpressionB = false ||\n                        \"\"\n                            .trim()\n                            .trim()\n                            .trim()\n                            .isEmpty()\n                        ?: true\n                \"\"\"),\n            singleConfiguration = true)\n        fun `case 2`() = Unit\n\n        @IndentationTest(\n            IndentedSourceCode(\n                \"\"\"\n                val elvisExpressionInsideBinaryExpressionC = true &&\n                        null as Boolean?\n                        ?: true\n                \"\"\"),\n            singleConfiguration = true)\n        fun `case 3`() = Unit\n\n        @IndentationTest(\n            IndentedSourceCode(\n                \"\"\"\n                val elvisExpressionInsideBinaryExpressionD = false ||\n                        (null as Boolean?)\n                        ?: true\n                \"\"\"),\n            singleConfiguration = true)\n        fun `case 4`() = Unit\n\n        @IndentationTest(\n            IndentedSourceCode(\n                \"\"\"\n                val elvisExpressionInsideBinaryExpressionE = true &&\n                        (42 as? Boolean)\n                        ?: true\n                \"\"\"),\n            singleConfiguration = true)\n        fun `case 5`() = Unit\n\n        /**\n         * _Elvis_ after a _safe-access_ expression should have the same\n         * indentation level as the previous function calls.\n         */\n        @IndentationTest(\n            IndentedSourceCode(\n                \"\"\"\n                val elvisAfterSafeAccess = \"\"\n                    ?.trim()\n                    ?.trim()\n                    ?.trim()\n                    ?.isEmpty()\n                    ?: \"\"\n                \"\"\"),\n            singleConfiguration = true)\n        fun `case 6`() = Unit\n\n        /**\n         * _Elvis_ after a _dot-qualified_ expression should have the same\n         * indentation level as the previous function calls.\n         */\n        @IndentationTest(\n            IndentedSourceCode(\n                \"\"\"\n                val elvisAfterDotQualified = \"\"\n                    .trim()\n                    .trim()\n                    .trim()\n                    .isEmpty()\n                    ?: \"\"\n                \"\"\"),\n            singleConfiguration = true)\n        fun `case 7`() = Unit\n\n        @IndentationTest(\n            IndentedSourceCode(\n                \"\"\"\n                fun f(): Boolean {\n                    return list.getChildren(null)\n                        .none { it.elementType in badModifiers } &&\n                            classBody?.getAllChildrenWithType(FUN)\n                                ?.isEmpty()\n                            ?: false &&\n                            getFirstChildWithType(SUPER_TYPE_LIST) == null\n                }\n                \"\"\"),\n            singleConfiguration = true)\n        fun `case 8`() = Unit\n\n        @IndentationTest(\n            IndentedSourceCode(\n                \"\"\"\n                fun f(): Boolean {\n                    return classBody?.getFirstChildWithType(FUN) == null &&\n                            getFirstChildWithType(SUPER_TYPE_LIST) == null &&\n                            // if there is any prop with logic in accessor then don't recommend to convert class to data class\n                            classBody?.let(::areGoodProps)\n                            ?: true\n                }\n                \"\"\"),\n            singleConfiguration = true)\n        fun `case 9`() = Unit\n\n        @IndentationTest(\n            IndentedSourceCode(\n                \"\"\"\n                fun f(): Boolean {\n                    return block.getChildrenOfType<KtProperty>()\n                        .any { it.nameAsName == property.nameAsName && expression.node.isGoingAfter(it.node) } ||\n                            block.parent\n                                .let { it as? KtFunctionLiteral }\n                                ?.valueParameters\n                                ?.any { it.nameAsName == property.nameAsName }\n                            ?: false\n                }\n                \"\"\"),\n            singleConfiguration = true)\n        fun `case 10`() = Unit\n\n        @IndentationTest(\n            IndentedSourceCode(\n                \"\"\"\n                fun f(): Boolean {\n                    return blockExpression\n                        .statements\n                        .takeWhile { !it.isAncestor(this, true) }\n                        .mapNotNull { it as? KtProperty }\n                        .find {\n                            it.isLocal &&\n                                    it.hasInitializer() &&\n                                    it.name?.equals(getReferencedName())\n                                    ?: false\n                        }\n                }\n                \"\"\"),\n            singleConfiguration = true)\n        fun `case 11`() = Unit\n\n        @IndentationTest(\n            IndentedSourceCode(\n                \"\"\"\n                fun f(): Any {\n                    return siblings(forward = true, withItself = false)\n                        .filterNot { it.node.isPartOfComment() || it is PsiWhiteSpace }\n                        .takeWhile {\n                            // statements like `name.field = value` where name == propertyName\n                            it is KtBinaryExpression && it.node.findChildByType(OPERATION_REFERENCE)?.findChildByType(EQ) != null &&\n                                    (it.left as? KtDotQualifiedExpression)?.run {\n                                        (receiverExpression as? KtNameReferenceExpression)?.getReferencedName() == propertyName\n                                    }\n                                    ?: false\n                        }\n                }\n                \"\"\"),\n            singleConfiguration = true)\n        fun `case 12`() = Unit\n\n        @IndentationTest(\n            IndentedSourceCode(\n                \"\"\"\n                fun f(): Any {\n                    return blockExpression\n                        .statements\n                        .takeWhile { !it.isAncestor(this, true) }\n                        .mapNotNull { it as? KtProperty }\n                        .find {\n                            it.isLocal &&\n                                    it.hasInitializer() &&\n                                    it.name?.equals(getReferencedName())\n                                    ?: false\n                        }\n                }\n                \"\"\"),\n            singleConfiguration = true)\n        fun `case 13`() = Unit\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/test/kotlin/com/saveourtool/diktat/ruleset/chapter3/spaces/IndentationRuleTestSuite.kt",
    "content": "package com.saveourtool.diktat.ruleset.chapter3.spaces\n\nimport org.junit.platform.suite.api.SelectClasses\nimport org.junit.platform.suite.api.Suite\n\n/**\n * Runs all indentation rule tests.\n */\n@Suite\n@SelectClasses(\n    IndentationRuleWarnTest::class,\n    IndentationRuleFixTest::class,\n    IndentationRuleTest::class,\n)\nclass IndentationRuleTestSuite\n"
  },
  {
    "path": "diktat-rules/src/test/kotlin/com/saveourtool/diktat/ruleset/chapter3/spaces/IndentationRuleTestUtils.kt",
    "content": "@file:JvmName(\"IndentationRuleTestUtils\")\n@file:Suppress(\"HEADER_MISSING_IN_NON_SINGLE_CLASS_FILE\")\n\npackage com.saveourtool.diktat.ruleset.chapter3.spaces\n\nimport com.saveourtool.diktat.common.config.rules.RulesConfig\nimport com.saveourtool.diktat.ruleset.constants.Warnings.WRONG_INDENTATION\nimport com.saveourtool.diktat.ruleset.utils.NEWLINE\nimport com.saveourtool.diktat.ruleset.utils.indentation.IndentationConfig\nimport com.saveourtool.diktat.ruleset.utils.indentation.IndentationConfig.Companion.ALIGNED_PARAMETERS\nimport com.saveourtool.diktat.ruleset.utils.indentation.IndentationConfig.Companion.EXTENDED_INDENT_AFTER_OPERATORS\nimport com.saveourtool.diktat.ruleset.utils.indentation.IndentationConfig.Companion.EXTENDED_INDENT_BEFORE_DOT\nimport com.saveourtool.diktat.ruleset.utils.indentation.IndentationConfig.Companion.EXTENDED_INDENT_FOR_EXPRESSION_BODIES\nimport com.saveourtool.diktat.ruleset.utils.indentation.IndentationConfig.Companion.EXTENDED_INDENT_OF_PARAMETERS\nimport com.saveourtool.diktat.ruleset.utils.indentation.IndentationConfig.Companion.INDENTATION_SIZE\nimport com.saveourtool.diktat.ruleset.utils.indentation.IndentationConfig.Companion.NEWLINE_AT_END\n\n/**\n * @param configEntries the optional values which override the state of this\n *   [IndentationConfig].\n * @return the content of this [IndentationConfig] as a map, with some\n *   configuration entries overridden via [configEntries].\n */\ninternal fun IndentationConfig.withCustomParameters(vararg configEntries: Pair<String, Any>): Map<String, String> =\n    mutableMapOf(\n        ALIGNED_PARAMETERS to alignedParameters.toString(),\n        INDENTATION_SIZE to indentationSize.toString(),\n        NEWLINE_AT_END to newlineAtEnd.toString(),\n        EXTENDED_INDENT_OF_PARAMETERS to extendedIndentOfParameters.toString(),\n        EXTENDED_INDENT_FOR_EXPRESSION_BODIES to extendedIndentForExpressionBodies.toString(),\n        EXTENDED_INDENT_AFTER_OPERATORS to extendedIndentAfterOperators.toString(),\n        EXTENDED_INDENT_BEFORE_DOT to extendedIndentBeforeDot.toString(),\n    ).apply {\n        configEntries.forEach { (key, value) ->\n            this[key] = value.toString()\n        }\n    }\n\n/**\n * @param configEntries the optional values which override the state of this\n *   [IndentationConfig].\n * @return the content of this [IndentationConfig] as a map, with some\n *   configuration entries overridden via [configEntries].\n */\ninternal fun IndentationConfig.withCustomParameters(configEntries: Map<String, Any>): Map<String, String> =\n    withCustomParameters(*configEntries\n        .asSequence()\n        .map { (key, value) ->\n            key to value\n        }.toList()\n        .toTypedArray())\n\n/**\n * Converts this map to a list containing a single [RulesConfig].\n *\n * @return the list containing a single [RulesConfig] entry.\n */\ninternal fun Map<String, String>.asRulesConfigList(): List<RulesConfig> =\n    listOf(\n        RulesConfig(\n            name = WRONG_INDENTATION.name,\n            enabled = true,\n            configuration = this\n        )\n    )\n"
  },
  {
    "path": "diktat-rules/src/test/kotlin/com/saveourtool/diktat/ruleset/chapter3/spaces/IndentationRuleWarnTest.kt",
    "content": "package com.saveourtool.diktat.ruleset.chapter3.spaces\n\nimport com.saveourtool.diktat.common.config.rules.DIKTAT_RULE_SET_ID\nimport com.saveourtool.diktat.common.config.rules.RulesConfig\nimport com.saveourtool.diktat.ruleset.constants.Warnings.WRONG_INDENTATION\nimport com.saveourtool.diktat.ruleset.junit.NaturalDisplayName\nimport com.saveourtool.diktat.ruleset.rules.chapter3.files.IndentationRule\nimport com.saveourtool.diktat.ruleset.utils.indentation.IndentationConfig.Companion.ALIGNED_PARAMETERS\nimport com.saveourtool.diktat.ruleset.utils.indentation.IndentationConfig.Companion.EXTENDED_INDENT_AFTER_OPERATORS\nimport com.saveourtool.diktat.ruleset.utils.indentation.IndentationConfig.Companion.EXTENDED_INDENT_BEFORE_DOT\nimport com.saveourtool.diktat.ruleset.utils.indentation.IndentationConfig.Companion.EXTENDED_INDENT_FOR_EXPRESSION_BODIES\nimport com.saveourtool.diktat.ruleset.utils.indentation.IndentationConfig.Companion.EXTENDED_INDENT_OF_PARAMETERS\nimport com.saveourtool.diktat.ruleset.utils.indentation.IndentationConfig.Companion.INDENTATION_SIZE\nimport com.saveourtool.diktat.util.LintTestBase\nimport com.saveourtool.diktat.util.TEST_FILE_NAME\n\nimport com.saveourtool.diktat.api.DiktatError\nimport generated.WarningNames\nimport org.junit.jupiter.api.Tag\nimport org.junit.jupiter.api.Test\nimport org.junit.jupiter.api.TestMethodOrder\nimport org.junit.jupiter.api.io.TempDir\nimport java.nio.file.Path\n\n/**\n * Legacy indentation tests.\n *\n * Consider adding new tests to [IndentationRuleTest] instead.\n *\n * @see IndentationRuleTest\n */\n@Suppress(\"LargeClass\")\n@TestMethodOrder(NaturalDisplayName::class)\nclass IndentationRuleWarnTest : LintTestBase(::IndentationRule) {\n    private val ruleId = \"$DIKTAT_RULE_SET_ID:${IndentationRule.NAME_ID}\"\n    private val rulesConfigList = listOf(\n        RulesConfig(WRONG_INDENTATION.name, true,\n            mapOf(\n                EXTENDED_INDENT_OF_PARAMETERS to \"true\",\n                ALIGNED_PARAMETERS to \"true\",\n                EXTENDED_INDENT_FOR_EXPRESSION_BODIES to \"true\",\n                EXTENDED_INDENT_AFTER_OPERATORS to \"true\",\n                EXTENDED_INDENT_BEFORE_DOT to \"false\",\n                INDENTATION_SIZE to \"4\"\n            )\n        )\n    )\n    private val disabledOptionsRulesConfigList = listOf(\n        RulesConfig(WRONG_INDENTATION.name, true,\n            mapOf(\n                EXTENDED_INDENT_OF_PARAMETERS to \"false\",\n                ALIGNED_PARAMETERS to \"false\",\n                EXTENDED_INDENT_FOR_EXPRESSION_BODIES to \"false\",\n                EXTENDED_INDENT_AFTER_OPERATORS to \"false\",\n                EXTENDED_INDENT_BEFORE_DOT to \"false\",\n                INDENTATION_SIZE to \"4\"\n            )\n        )\n    )\n\n    @Test\n    @Tag(WarningNames.WRONG_INDENTATION)\n    fun `should warn if tabs are used in indentation`() {\n        lintMethod(\n            \"\"\"\n                    |class Example {\n                    |${\"\\t\"}val zero = 0\n                    |}\n                    |\n            \"\"\".trimMargin(),\n            DiktatError(2, 1, ruleId, \"${WRONG_INDENTATION.warnText()} tabs are not allowed for indentation\", true)\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.WRONG_INDENTATION)\n    fun `should warn if indent size is not 4 spaces`() {\n        lintMethod(\n            \"\"\"\n                    |class Example {\n                    |   val zero = 0\n                    |}\n                    |\n            \"\"\".trimMargin(),\n            DiktatError(2, 1, ruleId, warnText(4, 3), true)\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.WRONG_INDENTATION)\n    fun `should warn if no new line at the end of file`(@TempDir tempDir: Path) {\n        lintMethodWithFile(\n            \"\"\"\n                    |class Example {\n                    |    val zero = 0\n                    |}\n            \"\"\".trimMargin(),\n            tempDir = tempDir,\n            fileName = TEST_FILE_NAME,\n            DiktatError(3, 1, ruleId, \"${WRONG_INDENTATION.warnText()} no newline at the end of file $TEST_FILE_NAME\", true)\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.WRONG_INDENTATION)\n    fun `should warn if no new line at the end of file, last child whitespace`(@TempDir tempDir: Path) {\n        lintMethodWithFile(\n            \"\"\"\n                |class Example {\n                |    val zero = 0\n                |}\n            \"\"\".trimMargin(),\n            tempDir = tempDir,\n            fileName = TEST_FILE_NAME,\n            DiktatError(3, 1, ruleId, \"${WRONG_INDENTATION.warnText()} no newline at the end of file $TEST_FILE_NAME\", true)\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.WRONG_INDENTATION)\n    fun `should warn if too many blank lines at the end of file`(@TempDir tempDir: Path) {\n        lintMethodWithFile(\n            \"\"\"\n                    |class Example {\n                    |    val zero = 0\n                    |}\n                    |\n                    |\n            \"\"\".trimMargin(),\n            tempDir = tempDir,\n            fileName = TEST_FILE_NAME,\n            DiktatError(5, 1, ruleId, \"${WRONG_INDENTATION.warnText()} too many blank lines at the end of file $TEST_FILE_NAME\", true)\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.WRONG_INDENTATION)\n    fun `valid indentation - example 1`() {\n        lintMethod(\n            \"\"\"\n                    |class Example {\n                    |    private val foo = 0\n                    |    private val fuu =\n                    |        0\n                    |\n                    |    fun bar() {\n                    |        if (foo > 0) {\n                    |            baz()\n                    |        } else {\n                    |            bazz()\n                    |        }\n                    |        return foo\n                    |    }\n                    |}\n                    |\n            \"\"\".trimMargin()\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.WRONG_INDENTATION)\n    fun `parameters can be indented by 8 spaces - positive example`() {\n        lintMethod(\n            \"\"\"\n                    |class Example(\n                    |        val field1: Type1,\n                    |        val field2: Type2,\n                    |        val field3: Type3\n                    |) {\n                    |    val e1 = Example(\n                    |            t1,\n                    |            t2,\n                    |            t3\n                    |    )\n                    |\n                    |    val e2 = Example(t1, t2,\n                    |            t3\n                    |    )\n                    |}\n                    |\n            \"\"\".trimMargin(),\n            rulesConfigList = rulesConfigList\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.WRONG_INDENTATION)\n    fun `parameters can be aligned - positive example`() {\n        lintMethod(\n            \"\"\"\n                    |class Example(val field1: Type1,\n                    |              val field2: Type2,\n                    |              val field3: Type3) {\n                    |}\n                    |\n            \"\"\".trimMargin(),\n            rulesConfigList = rulesConfigList\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.WRONG_INDENTATION)\n    fun `parameters can be aligned`() {\n        lintMethod(\n            \"\"\"\n                    |class Example(\n                    |              val field1: Type1,\n                    |              val field2: Type2,\n                    |              val field3: Type3) {\n                    |}\n                    |\n            \"\"\".trimMargin(),\n            DiktatError(2, 1, ruleId, warnText(8, 14), true),\n            DiktatError(3, 1, ruleId, warnText(8, 14), true),\n            DiktatError(4, 1, ruleId, warnText(8, 14), true),\n            rulesConfigList = rulesConfigList\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.WRONG_INDENTATION)\n    fun `lines split by operator can be indented by 8 spaces`() {\n        lintMethod(\n            \"\"\"\n                    |fun foo(a: Int, b: Int) {\n                    |    return 2 * a +\n                    |            b\n                    |}\n                    |\n            \"\"\".trimMargin(),\n            rulesConfigList = rulesConfigList\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.WRONG_INDENTATION)\n    fun `should check indentation in KDocs - positive example`() {\n        lintMethod(\n            \"\"\"\n                    |/**\n                    | * Lorem ipsum\n                    | */\n                    |class Example {\n                    |}\n                    |\n            \"\"\".trimMargin()\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.WRONG_INDENTATION)\n    fun `assignment increases indentation if followed by newline`() {\n        lintMethod(\n            \"\"\"\n                    |fun <T> foo(list: List<T>) {\n                    |    val a = list.filter {\n                    |        predicate(it)\n                    |    }\n                    |\n                    |    val b =\n                    |        list.filter {\n                    |            predicate(it)\n                    |        }\n                    |}\n                    |\n            \"\"\".trimMargin()\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.WRONG_INDENTATION)\n    fun `when lambda is assigned, indentation is increased by one step`() {\n        lintMethod(\n            \"\"\"\n                    |fun foo() {\n                    |    val a = { x: Int ->\n                    |        x * 2\n                    |    }\n                    |\n                    |    val b =\n                    |        { x: Int ->\n                    |            x * 2\n                    |        }\n                    |}\n                    |\n            \"\"\".trimMargin()\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.WRONG_INDENTATION)\n    fun `should check indentation in KDocs`() {\n        lintMethod(\n            \"\"\"\n                    |/**\n                    |* Lorem ipsum\n                    |*/\n                    |class Example {\n                    |}\n                    |\n            \"\"\".trimMargin(),\n            DiktatError(2, 1, ruleId, warnText(1, 0), true),\n            DiktatError(3, 1, ruleId, warnText(1, 0), true)\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.WRONG_INDENTATION)\n    fun `dot call increases indentation`() {\n        lintMethod(\n            \"\"\"\n                    |fun foo() {\n                    |    Integer\n                    |        .valueOf(2).also {\n                    |            println(it)\n                    |        }\n                    |        ?.also {\n                    |            println(\"Also with safe access\")\n                    |        }\n                    |        ?: Integer.valueOf(0)\n                    |\n                    |    bar\n                    |        .baz()\n                    |            as Baz\n                    |            as? Baz\n                    |}\n                    |\n            \"\"\".trimMargin()\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.WRONG_INDENTATION)\n    fun `loops and conditionals without braces should be indented - positive example`() {\n        lintMethod(\n            \"\"\"\n                    |fun foo() {\n                    |    for (i in 1..100)\n                    |        println(i)\n                    |\n                    |    do\n                    |        println()\n                    |    while (condition)\n                    |\n                    |    if (condition)\n                    |        bar()\n                    |    else\n                    |        baz()\n                    |}\n                    |\n            \"\"\".trimMargin()\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.WRONG_INDENTATION)\n    fun `loops and conditionals without braces should be indented`() {\n        lintMethod(\n            \"\"\"\n                    |fun foo() {\n                    |    for (i in 1..100)\n                    |    println(i)\n                    |\n                    |    do\n                    |    println()\n                    |    while (condition)\n                    |\n                    |    if (condition)\n                    |    bar()\n                    |    else\n                    |    baz()\n                    |}\n                    |\n            \"\"\".trimMargin(),\n            DiktatError(3, 1, ruleId, warnText(8, 4), true),\n            DiktatError(6, 1, ruleId, warnText(8, 4), true),\n            DiktatError(10, 1, ruleId, warnText(8, 4), true),\n            DiktatError(12, 1, ruleId, warnText(8, 4), true)\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.WRONG_INDENTATION)\n    fun `loops and conditionals without braces should be indented - if-else with mixed braces`() {\n        lintMethod(\n            \"\"\"\n                    |fun foo() {\n                    |    if (condition) {\n                    |        bar()\n                    |    } else\n                    |        baz()\n                    |\n                    |    if (condition)\n                    |        bar()\n                    |    else {\n                    |        baz()\n                    |    }\n                    |\n                    |    if (condition)\n                    |        bar()\n                    |    else if (condition2) {\n                    |        baz()\n                    |    } else\n                    |        qux()\n                    |\n                    |    if (condition)\n                    |        bar()\n                    |    else if (condition2)\n                    |        baz()\n                    |    else {\n                    |        quux()\n                    |    }\n                    |}\n                    |\n            \"\"\".trimMargin()\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.WRONG_INDENTATION)\n    fun `opening braces should not increase indent when placed on the same line`() {\n        lintMethod(\n            \"\"\"\n                    |fun foo() {\n                    |    consume(Example(\n                    |        t1, t2, t3\n                    |    ))\n                    |\n                    |    bar(baz(\n                    |        1,\n                    |        2\n                    |    )\n                    |    )\n                    |\n                    |    bar(baz(\n                    |        1,\n                    |        2),\n                    |        3\n                    |    )\n                    |}\n                    |\n            \"\"\".trimMargin()\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.WRONG_INDENTATION)\n    fun `opening braces should not increase indent when placed on the same line - with disabled options`() {\n        lintMethod(\n            \"\"\"\n                    |fun foo() {\n                    |    bar(baz(\n                    |        1,\n                    |        2),\n                    |        3\n                    |    )\n                    |}\n                    |\n            \"\"\".trimMargin(),\n            rulesConfigList = disabledOptionsRulesConfigList\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.WRONG_INDENTATION)\n    fun `custom getters and setters should increase indentation - positive example`() {\n        lintMethod(\n            \"\"\"\n                    |class Example {\n                    |    private val foo\n                    |        get() = 0\n                    |\n                    |    private var backing = 0\n                    |\n                    |    var bar\n                    |        get() = backing\n                    |        set(value) { backing = value }\n                    |}\n                    |\n            \"\"\".trimMargin()\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.WRONG_INDENTATION)\n    fun `custom getters and setters should increase indentation`() {\n        lintMethod(\n            \"\"\"\n                    |class Example {\n                    |    private val foo\n                    |            get() = 0\n                    |\n                    |    private var backing = 0\n                    |\n                    |    var bar\n                    |    get() = backing\n                    |    set(value) { backing = value }\n                    |}\n                    |\n            \"\"\".trimMargin(),\n            DiktatError(3, 1, ruleId, warnText(8, 12), true),\n            DiktatError(8, 1, ruleId, warnText(8, 4), true),\n            DiktatError(9, 1, ruleId, warnText(8, 4), true)\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.WRONG_INDENTATION)\n    fun `regression - indentation should be increased inside parameter list for multiline parameters`() {\n        lintMethod(\n            \"\"\"\n                    |fun foo() {\n                    |    bar(\n                    |        param1 = baz(\n                    |            1,\n                    |            2\n                    |        ),\n                    |        param2 = { elem ->\n                    |            elem.qux()\n                    |        },\n                    |        param3 = x\n                    |            .y()\n                    |    )\n                    |}\n                    |\n            \"\"\".trimMargin()\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.WRONG_INDENTATION)\n    fun `regression - nested blocks inside loops and conditionals without braces should be properly indented`() {\n        lintMethod(\n            \"\"\"\n                    |fun foo() {\n                    |    if (condition)\n                    |        list.filter {\n                    |            bar()\n                    |        }\n                    |            .call(\n                    |                param1,\n                    |                param2\n                    |            )\n                    |    else\n                    |        list\n                    |            .filter {\n                    |                baz()\n                    |            }\n                    |}\n                    |\n            \"\"\".trimMargin(),\n            rulesConfigList = listOf(\n                RulesConfig(WRONG_INDENTATION.name, true,\n                    mapOf(\n                        EXTENDED_INDENT_OF_PARAMETERS to \"false\",\n                        EXTENDED_INDENT_BEFORE_DOT to \"false\"\n                    )\n                )\n            )\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.WRONG_INDENTATION)\n    fun `arrows in when expression should increase indentation - positive example`() {\n        lintMethod(\n            \"\"\"\n                    |fun foo() {\n                    |    when (x) {\n                    |        X_1 ->\n                    |            foo(x)\n                    |        X_2 -> bar(x)\n                    |        X_3 -> {\n                    |            baz(x)\n                    |        }\n                    |        else ->\n                    |            qux(x)\n                    |    }\n                    |}\n                    |\n            \"\"\".trimMargin()\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.WRONG_INDENTATION)\n    fun `arrows in when expression should increase indentation`() {\n        lintMethod(\n            \"\"\"\n                    |fun foo() {\n                    |    when (x) {\n                    |        X_1 ->\n                    |        foo(x)\n                    |        X_2 -> bar(x)\n                    |        X_3 -> {\n                    |        baz(x)\n                    |        }\n                    |        else ->\n                    |        qux(x)\n                    |    }\n                    |}\n                    |\n            \"\"\".trimMargin(),\n            DiktatError(4, 1, ruleId, warnText(12, 8), true),\n            DiktatError(7, 1, ruleId, warnText(12, 8), true),\n            DiktatError(10, 1, ruleId, warnText(12, 8), true)\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.WRONG_INDENTATION)\n    fun `comments should not turn off exceptional indentation`() {\n        lintMethod(\n            \"\"\"\n                    |fun foo() {\n                    |    list\n                    |        .map(::foo)\n                    |        // comment about the next call\n                    |        .filter { it.bar() }\n                    |        // another comment about the next call\n                    |        ?.filter { it.bar() }\n                    |        ?.count()\n                    |\n                    |    list.any { predicate(it) } &&\n                    |            list.any {\n                    |                predicate(it)\n                    |            }\n                    |\n                    |    list.any { predicate(it) } &&\n                    |            // comment\n                    |            list.any {\n                    |                predicate(it)\n                    |            }\n                    |\n                    |    list.filter {\n                    |        predicate(it) &&\n                    |                // comment\n                    |                predicate(it)\n                    |    }\n                    |}\n                    |\n            \"\"\".trimMargin()\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.WRONG_INDENTATION)\n    fun `regression - npe with comments`() {\n        lintMethod(\n            \"\"\"\n                |fun foo() {\n                |    bar.let {\n                |        baz(it)\n                |        // lorem ipsum\n                |    }\n                |}\n                |\n            \"\"\".trimMargin()\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.WRONG_INDENTATION)\n    fun `closing parenthesis bug`() {\n        lintMethod(\n            \"\"\"\n                    |fun foo() {\n                    |    return x +\n                    |            (y +\n                    |                    foo(x)\n                    |            )\n                    |}\n                    |\n            \"\"\".trimMargin()\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.WRONG_INDENTATION)\n    fun `should trigger on string templates starting with new line`() {\n        lintMethod(\n            \"\"\"\n                |fun foo(some: String) {\n                |    fun bar() {\n                |        val a = \"${'$'}{\n                |        expression\n                |            .foo()\n                |            .bar()\n                |        }\"\n                |    }\n                |\n                |    val b = \"${'$'}{ foo().bar() }\"\n                |}\n                |\n            \"\"\".trimMargin(),\n            DiktatError(4, 1, ruleId, warnText(12, 8), true),\n            DiktatError(5, 1, ruleId, warnText(16, 12), true),\n            DiktatError(6, 1, ruleId, warnText(16, 12), true),\n            rulesConfigList = rulesConfigList\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.WRONG_INDENTATION)\n    fun `check script`(@TempDir tempDir: Path) {\n        lintMethodWithFile(\n            \"\"\"\n                |val q = 1\n                |\n            \"\"\".trimMargin(),\n            tempDir = tempDir,\n            fileName = \"src/main/kotlin/com/saveourtool/diktat/Example.kts\"\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.WRONG_INDENTATION)\n    fun `check gradle script`(@TempDir tempDir: Path) {\n        lintMethodWithFile(\n            \"\"\"\n                |projectName = \"diKTat\"\n                |\n            \"\"\".trimMargin(),\n            tempDir = tempDir,\n            fileName = \"src/main/kotlin/com/saveourtool/diktat/build.gradle.kts\"\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.WRONG_INDENTATION)\n    fun `should warn message with configured indentation size`() {\n        val rulesConfigListWithIndentation2 = rulesConfigList.map { ruleConfig ->\n            ruleConfig.copy(configuration = ruleConfig.configuration.mapValues { (key, value) ->\n                if (key == INDENTATION_SIZE) {\n                    \"2\"\n                } else {\n                    value\n                }\n            })\n        }\n        val warnMessage = WRONG_INDENTATION.warnText().replace(\"4\", \"2\")\n        lintMethod(\n            \"\"\"\n                |fun foo(some: String) {\n                |    print(\"test\")\n                |if (test){\n                |print(\"2\")\n                |}\n                |}\n                |\n            \"\"\".trimMargin(),\n            DiktatError(2, 1, ruleId, \"$warnMessage expected 2 but was 4\", true),\n            DiktatError(3, 1, ruleId, \"$warnMessage expected 2 but was 0\", true),\n            DiktatError(4, 1, ruleId, \"$warnMessage expected 4 but was 0\", true),\n            DiktatError(5, 1, ruleId, \"$warnMessage expected 2 but was 0\", true),\n            rulesConfigList = rulesConfigListWithIndentation2\n        )\n    }\n\n    private fun warnText(expected: Int, actual: Int) = \"${WRONG_INDENTATION.warnText()} expected $expected but was $actual\"\n}\n"
  },
  {
    "path": "diktat-rules/src/test/kotlin/com/saveourtool/diktat/ruleset/chapter3/spaces/WhiteSpaceRuleFixTest.kt",
    "content": "package com.saveourtool.diktat.ruleset.chapter3.spaces\n\nimport com.saveourtool.diktat.ruleset.rules.chapter3.files.WhiteSpaceRule\nimport com.saveourtool.diktat.util.FixTestBase\n\nimport generated.WarningNames\nimport org.junit.jupiter.api.Tag\nimport org.junit.jupiter.api.Test\n\nclass WhiteSpaceRuleFixTest : FixTestBase(\"test/paragraph3/spaces\", ::WhiteSpaceRule) {\n    @Test\n    @Tag(WarningNames.WRONG_WHITESPACE)\n    fun `should keep single whitespace between keyword and opening parentheses`() {\n        fixAndCompare(\"WhiteSpaceBeforeLParExpected.kt\", \"WhiteSpaceBeforeLParTest.kt\")\n    }\n\n    @Test\n    @Tag(WarningNames.WRONG_WHITESPACE)\n    fun `should keep single whitespace between keyword and opening brace`() {\n        fixAndCompare(\"LBraceAfterKeywordExpected.kt\", \"LBraceAfterKeywordTest.kt\")\n    }\n\n    @Test\n    @Tag(WarningNames.WRONG_WHITESPACE)\n    fun `should remove spaces between ( and { when lambda is used as an argument`() {\n        fixAndCompare(\"LambdaAsArgumentExpected.kt\", \"LambdaAsArgumentTest.kt\")\n    }\n\n    @Test\n    @Tag(WarningNames.WRONG_WHITESPACE)\n    fun `should keep single whitespace before any other opening brace`() {\n        fixAndCompare(\"LbraceExpected.kt\", \"LbraceTest.kt\")\n    }\n\n    @Test\n    @Tag(WarningNames.WRONG_WHITESPACE)\n    fun `should surround binary operators with spaces`() {\n        fixAndCompare(\"BinaryOpExpected.kt\", \"BinaryOpTest.kt\")\n    }\n\n    @Test\n    @Tag(WarningNames.WRONG_WHITESPACE)\n    fun `should trim spaces in the end of line`() {\n        fixAndCompare(\"EolSpacesExpected.kt\", \"EolSpacesTest.kt\")\n    }\n\n    @Test\n    @Tag(WarningNames.WRONG_WHITESPACE)\n    fun `should fix space in annotation`() {\n        fixAndCompare(\"AnnotationExpected.kt\", \"AnnotationTest.kt\")\n    }\n\n    @Test\n    @Tag(WarningNames.WRONG_WHITESPACE)\n    fun `should add spaces on both sides of equals`() {\n        fixAndCompare(\"EqualsExpected.kt\", \"EqualsTest.kt\")\n    }\n\n    @Test\n    @Tag(WarningNames.WRONG_WHITESPACE)\n    fun `should add spaces on both sides of braces in lambda`() {\n        fixAndCompare(\"BracesLambdaSpacesExpected.kt\", \"BracesLambdaSpacesTest.kt\")\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/test/kotlin/com/saveourtool/diktat/ruleset/chapter3/spaces/WhiteSpaceRuleWarnTest.kt",
    "content": "package com.saveourtool.diktat.ruleset.chapter3.spaces\n\nimport com.saveourtool.diktat.common.config.rules.DIKTAT_RULE_SET_ID\nimport com.saveourtool.diktat.ruleset.constants.Warnings.WRONG_WHITESPACE\nimport com.saveourtool.diktat.ruleset.rules.chapter3.files.WhiteSpaceRule\nimport com.saveourtool.diktat.util.LintTestBase\n\nimport com.saveourtool.diktat.api.DiktatError\nimport generated.WarningNames\nimport org.junit.jupiter.api.Tag\nimport org.junit.jupiter.api.Test\n\n@Suppress(\"LargeClass\")\nclass WhiteSpaceRuleWarnTest : LintTestBase(::WhiteSpaceRule) {\n    private val ruleId = \"$DIKTAT_RULE_SET_ID:${WhiteSpaceRule.NAME_ID}\"\n    private val eolSpaceWarn = \"${WRONG_WHITESPACE.warnText()} there should be no spaces in the end of line\"\n    private val lbraceWarn = \"${WRONG_WHITESPACE.warnText()} there should be a whitespace before '{'\"\n    private fun keywordWarn(keyword: String, sep: String) =\n        \"${WRONG_WHITESPACE.warnText()} keyword '$keyword' should be separated from '$sep' with a whitespace\"\n\n    private fun tokenWarn(token: String,\n                          before: Int?,\n                          after: Int?,\n                          reqBefore: Int?,\n                          reqAfter: Int?\n    ) = \"${WRONG_WHITESPACE.warnText()} $token should have\" +\n            (reqBefore?.let { \" $it space(s) before\" } ?: \"\") +\n            (if (reqBefore != null && reqAfter != null) \" and\" else \"\") +\n            (reqAfter?.let { \" $it space(s) after\" } ?: \"\") +\n            \", but has\" +\n            (before?.let { \" $it space(s) before\" } ?: \"\") +\n            (if (before != null && after != null) \" and\" else \"\") +\n            (after?.let { \" $it space(s) after\" } ?: \"\")\n\n    @Test\n    @Tag(WarningNames.WRONG_WHITESPACE)\n    fun `keywords should have space before opening parenthesis and braces - positive example`() {\n        lintMethod(\n            \"\"\"\n                    |class Example {\n                    |    constructor(val a: Int)\n                    |\n                    |    fun foo() {\n                    |         if (condition) { }\n                    |         else { }\n                    |         for (i in 1..100) { }\n                    |         when (expression) { }\n                    |    }\n                    |}\n            \"\"\".trimMargin()\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.WRONG_WHITESPACE)\n    fun `keywords should have space before opening parenthesis`() {\n        lintMethod(\n            \"\"\"\n                    |class Example {\n                    |    fun foo() {\n                    |        if(condition) { }\n                    |        for  (i in 1..100) { }\n                    |        when(expression) { }\n                    |    }\n                    |}\n            \"\"\".trimMargin(),\n            DiktatError(3, 11, ruleId, keywordWarn(\"if\", \"(\"), true),\n            DiktatError(4, 14, ruleId, keywordWarn(\"for\", \"(\"), true),\n            DiktatError(5, 13, ruleId, keywordWarn(\"when\", \"(\"), true)\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.WRONG_WHITESPACE)\n    fun `constructor should not have space before opening parenthesis`() {\n        lintMethod(\n            \"\"\"\n                    |class Example {\n                    |    constructor (val a: Int)\n                    |}\n            \"\"\".trimMargin(),\n            DiktatError(2, 5, ruleId, \"${WRONG_WHITESPACE.warnText()} keyword 'constructor' should not be separated from '(' with a whitespace\", true)\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.WRONG_WHITESPACE)\n    fun `keywords should have space before opening braces`() {\n        lintMethod(\n            \"\"\"\n                    |class Example {\n                    |    fun foo() {\n                    |         if (condition) { }\n                    |         else{}\n                    |         try{ }\n                    |         finally{ }\n                    |    }\n                    |}\n            \"\"\".trimMargin(),\n            DiktatError(4, 14, ruleId, keywordWarn(\"else\", \"{\"), true),\n            DiktatError(5, 13, ruleId, keywordWarn(\"try\", \"{\"), true),\n            DiktatError(6, 17, ruleId, keywordWarn(\"finally\", \"{\"), true)\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.WRONG_WHITESPACE)\n    fun `keywords should have space before opening braces - else without braces`() {\n        lintMethod(\n            \"\"\"\n                    |fun foo() {\n                    |     if (condition)\n                    |         bar()\n                    |     else\n                    |         baz()\n                    |\n                    |     if (condition) bar() else  baz()\n                    |}\n            \"\"\".trimMargin(),\n            DiktatError(7, 33, ruleId, keywordWarn(\"else\", \"baz\"), true)\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.WRONG_WHITESPACE)\n    fun `all opening braces should have leading space`() {\n        lintMethod(\n            \"\"\"\n                    |class Example{\n                    |    fun foo(){\n                    |        list.run{\n                    |            map{ bar(it) }\n                    |        }\n                    |    }\n                    |}\n            \"\"\".trimMargin(),\n            DiktatError(1, 14, ruleId, lbraceWarn, true),\n            DiktatError(2, 14, ruleId, lbraceWarn, true),\n            DiktatError(3, 17, ruleId, lbraceWarn, true),\n            DiktatError(4, 16, ruleId, lbraceWarn, true)\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.WRONG_WHITESPACE)\n    fun `all opening braces should have leading space - exception for lambdas as arguments`() {\n        lintMethod(\n            \"\"\"\n                    |fun foo(a: (Int) -> Int, b: Int) {\n                    |    foo({ x: Int -> x }, 5)\n                    |}\n                    |\n                    |fun bar(a: (Int) -> Int, b: Int) {\n                    |    bar( { x: Int -> x }, 5)\n                    |}\n                    |\n                    |val lambda = { x: Int -> 2 * x }\n            \"\"\".trimMargin(),\n            DiktatError(6, 10, ruleId, \"${WRONG_WHITESPACE.warnText()} there should be no whitespace before '{' of lambda inside argument list\", true)\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.WRONG_WHITESPACE)\n    fun `binary operators should be surrounded by spaces - positive example`() {\n        lintMethod(\n            \"\"\"\n                    |class Example<T> where T : UpperType {\n                    |    fun foo(t: T) = t + 1\n                    |\n                    |    fun bar() {\n                    |        listOf<T>().map(this::foo).filter { elem -> predicate(elem) }\n                    |    }\n                    |}\n            \"\"\".trimMargin()\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.WRONG_WHITESPACE)\n    fun `should not false positively trigger when operators are surrounded with newlines`() {\n        lintMethod(\n            \"\"\"\n                    |class Example<T> where T\n                    |                 :\n                    |                 UpperType {\n                    |    fun foo(t: T) =\n                    |            t + 1\n                    |\n                    |    fun bar() {\n                    |        listOf<T>()\n                    |            .map(this\n                    |                ::foo)\n                    |            .filter { elem ->\n                    |                 predicate(elem)\n                    |             }\n                    |    }\n                    |}\n            \"\"\".trimMargin()\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.WRONG_WHITESPACE)\n    fun `should not false positively trigger when operators are surrounded with newlines and EOL comments`() {\n        lintMethod(\n            \"\"\"\n                    |class Example<T> where T\n                    |                 :  // comment about UpperType\n                    |                 UpperType {\n                    |    fun foo(t: T) =  // another comment\n                    |            t + 1\n                    |\n                    |    fun bar() {\n                    |        listOf<T>()\n                    |            .map(this  // lorem ipsum\n                    |                ::foo)\n                    |            .filter { elem ->  // dolor sit amet\n                    |                 predicate(elem)\n                    |             }\n                    |    }\n                    |}\n            \"\"\".trimMargin()\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.WRONG_WHITESPACE)\n    @Suppress(\"TOO_LONG_FUNCTION\")\n    fun `binary operators should be surrounded by spaces`() {\n        lintMethod(\n            \"\"\"\n                    |class Example<T, R, Q> where T:UpperType, R: UpperType, Q :UpperType {\n                    |    fun foo(t: T) = t+ 1\n                    |    fun foo2(t: T) = t+1\n                    |    fun foo3(t: T) = t +1\n                    |\n                    |    fun bar() {\n                    |        listOf<T>() .map(this ::foo) ?.filter { elem ->predicate(elem) } !!.first()\n                    |        listOf<T>() . map(this :: foo) ?. filter { elem->predicate(elem) } !! .first()\n                    |        listOf<T>(). map(this:: foo)?. filter { elem-> predicate(elem) }!!. first()\n                    |    }\n                    |}\n            \"\"\".trimMargin(),\n            DiktatError(1, 31, ruleId, tokenWarn(\":\", 0, 0, 1, 1), true),\n            DiktatError(1, 44, ruleId, tokenWarn(\":\", 0, null, 1, 1), true),\n            DiktatError(1, 59, ruleId, tokenWarn(\":\", null, 0, 1, 1), true),\n            DiktatError(2, 22, ruleId, tokenWarn(\"+\", 0, null, 1, 1), true),\n            DiktatError(3, 23, ruleId, tokenWarn(\"+\", 0, 0, 1, 1), true),\n            DiktatError(4, 24, ruleId, tokenWarn(\"+\", null, 0, 1, 1), true),\n            DiktatError(7, 21, ruleId, tokenWarn(\".\", 1, null, 0, 0), true),\n            DiktatError(7, 31, ruleId, tokenWarn(\"::\", 1, null, 0, 0), true),\n            DiktatError(7, 38, ruleId, tokenWarn(\"?.\", 1, null, 0, 0), true),\n            DiktatError(7, 54, ruleId, tokenWarn(\"->\", null, 0, 1, 1), true),\n            DiktatError(7, 74, ruleId, tokenWarn(\"!!\", 1, null, 0, null), true),\n            DiktatError(8, 21, ruleId, tokenWarn(\".\", 1, 1, 0, 0), true),\n            DiktatError(8, 32, ruleId, tokenWarn(\"::\", 1, 1, 0, 0), true),\n            DiktatError(8, 40, ruleId, tokenWarn(\"?.\", 1, 1, 0, 0), true),\n            DiktatError(8, 56, ruleId, tokenWarn(\"->\", 0, 0, 1, 1), true),\n            DiktatError(8, 76, ruleId, tokenWarn(\"!!\", 1, null, 0, null), true),\n            DiktatError(8, 79, ruleId, tokenWarn(\".\", 1, null, 0, 0), true),\n            DiktatError(9, 20, ruleId, tokenWarn(\".\", null, 1, 0, 0), true),\n            DiktatError(9, 30, ruleId, tokenWarn(\"::\", null, 1, 0, 0), true),\n            DiktatError(9, 37, ruleId, tokenWarn(\"?.\", null, 1, 0, 0), true),\n            DiktatError(9, 53, ruleId, tokenWarn(\"->\", 0, null, 1, 1), true),\n            DiktatError(9, 75, ruleId, tokenWarn(\".\", null, 1, 0, 0), true)\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.WRONG_WHITESPACE)\n    fun `operators with single space after - positive example`() {\n        lintMethod(\n            \"\"\"\n                    |class Example<T> {\n                    |    fun foo(t1: T, t2: T) {\n                    |        println(); println()\n                    |    }\n                    |\n                    |    fun bar(t: T,\n                    |            d: T) {\n                    |        println();\n                    |    }\n                    |\n                    |    val x: Int\n                    |}\n            \"\"\".trimMargin()\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.WRONG_WHITESPACE)\n    fun `operators with single space after`() {\n        lintMethod(\n            \"\"\"\n                    |class Example<T> {${\" \"}\n                    |    fun foo(t1 :T ,t2:T) {${\" \"}\n                    |        println();println()\n                    |        println() ; println()\n                    |    }\n                    |\n                    |    val x : Int\n                    |}\n            \"\"\".trimMargin(),\n            DiktatError(1, 19, ruleId, eolSpaceWarn, true),\n            DiktatError(2, 16, ruleId, tokenWarn(\":\", 1, 0, 0, 1), true),\n            DiktatError(2, 19, ruleId, tokenWarn(\",\", 1, 0, 0, 1), true),\n            DiktatError(2, 22, ruleId, tokenWarn(\":\", null, 0, 0, 1), true),\n            DiktatError(2, 27, ruleId, eolSpaceWarn, true),\n            DiktatError(3, 18, ruleId, tokenWarn(\";\", null, 0, 0, 1), true),\n            DiktatError(4, 19, ruleId, tokenWarn(\";\", 1, null, 0, 1), true),\n            DiktatError(7, 11, ruleId, tokenWarn(\":\", 1, null, 0, 1), true)\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.WRONG_WHITESPACE)\n    fun `operators with single space after - exceptional cases - positive example`() {\n        lintMethod(\n            \"\"\"\n                    |abstract class Foo<out T : Any> : IFoo { }\n                    |\n                    |class FooImpl : Foo() {\n                    |    constructor(x: String) : this(x) { /*...*/ }\n                    |\n                    |    val x = object : IFoo { /*...*/ }\n                    |}\n            \"\"\".trimMargin()\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.WRONG_WHITESPACE)\n    fun `operators with single space after - exceptional cases`() {\n        lintMethod(\n            \"\"\"\n                    |abstract class Foo<out T: Any>: IFoo { }\n                    |\n                    |class FooImpl: Foo() {\n                    |    constructor(x: String): this(x) { /*...*/ }\n                    |\n                    |    val x = object: IFoo { /*...*/ }\n                    |}\n            \"\"\".trimMargin(),\n            DiktatError(1, 25, ruleId, tokenWarn(\":\", 0, null, 1, 1), true),\n            DiktatError(1, 31, ruleId, tokenWarn(\":\", 0, null, 1, 1), true),\n            DiktatError(3, 14, ruleId, tokenWarn(\":\", 0, null, 1, 1), true),\n            DiktatError(4, 27, ruleId, tokenWarn(\":\", 0, null, 1, 1), true),\n            DiktatError(6, 19, ruleId, tokenWarn(\":\", 0, null, 1, 1), true)\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.WRONG_WHITESPACE)\n    fun `there should be no space before question mark in nullable types`() {\n        lintMethod(\n            \"\"\"\n                    |class Example {\n                    |    lateinit var x: Int?\n                    |    lateinit var x: Int ?\n                    |}\n            \"\"\".trimMargin(),\n            DiktatError(3, 25, ruleId, tokenWarn(\"?\", 1, null, 0, null), true)\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.WRONG_WHITESPACE)\n    fun `there should be no space before and after square bracket`() {\n        lintMethod(\n            \"\"\"\n                    |val x = list[0]\n                    |val y = list [0]\n            \"\"\".trimMargin(),\n            DiktatError(2, 14, ruleId, tokenWarn(\"[\", 1, null, 0, 0), true)\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.WRONG_WHITESPACE)\n    fun `there should be no space between constructor or function name and opening parentheses - positive example`() {\n        lintMethod(\n            \"\"\"\n                    |class Example(val x: Int) {\n                    |    constructor() : this(0)\n                    |\n                    |    fun foo(y: Int): AnotherExample {\n                    |        bar(x)\n                    |        return AnotherExample(y)\n                    |    }\n                    |}\n            \"\"\".trimMargin()\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.WRONG_WHITESPACE)\n    fun `there should be no space between constructor or function name and opening parentheses`() {\n        lintMethod(\n            \"\"\"\n                    |class Example (val x: Int) {\n                    |    constructor() : this (0)\n                    |\n                    |    fun foo (y: Int): AnotherExample {\n                    |        bar (x)\n                    |        return AnotherExample (y)\n                    |    }\n                    |}\n            \"\"\".trimMargin(),\n            DiktatError(1, 15, ruleId, tokenWarn(\"(\", 1, null, 0, 0), true),\n            DiktatError(2, 26, ruleId, tokenWarn(\"(\", 1, null, 0, 0), true),\n            DiktatError(4, 13, ruleId, tokenWarn(\"(\", 1, null, 0, 0), true),\n            DiktatError(5, 13, ruleId, tokenWarn(\"(\", 1, null, 0, 0), true),\n            DiktatError(6, 31, ruleId, tokenWarn(\"(\", 1, null, 0, 0), true)\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.WRONG_WHITESPACE)\n    fun `there should be no space before and single space after colon in function return type`() {\n        lintMethod(\n            \"\"\"\n                    |fun foo(): String = \"lorem\"\n                    |fun bar() : String = \"ipsum\"\n                    |fun baz() :String = \"dolor\"\n            \"\"\".trimMargin(),\n            DiktatError(2, 11, ruleId, tokenWarn(\":\", 1, null, 0, 1), true),\n            DiktatError(3, 11, ruleId, tokenWarn(\":\", 1, 0, 0, 1), true)\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.WRONG_WHITESPACE)\n    fun `there should be no space before and after colon when use-site annotation is used`() {\n        lintMethod(\n            \"\"\"\n                    |class Example(@field:Anno val foo: Type,\n                    |              @get:Anno val bar: Type,\n                    |              @param:Anno val baz: Type)\n                    |\n                    |class Example2(@field: Anno val foo: Type,\n                    |               @get :Anno val bar: Type,\n                    |               @param : Anno val baz: Type)\n            \"\"\".trimMargin(),\n            DiktatError(5, 22, ruleId, tokenWarn(\":\", null, 1, 0, 0), true),\n            DiktatError(6, 21, ruleId, tokenWarn(\":\", 1, null, 0, 0), true),\n            DiktatError(7, 23, ruleId, tokenWarn(\":\", 1, 1, 0, 0), true)\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.WRONG_WHITESPACE)\n    fun `regression - comma after !!`() {\n        lintMethod(\n            \"\"\"\n                    |fun foo() {\n                    |    val codeFix = CodeFix(codeForm.initialCode!! ,codeFormHtml.ruleSet[0])\n                    |}\n            \"\"\".trimMargin(),\n            DiktatError(2, 50, ruleId, tokenWarn(\",\", 1, 0, 0, 1), true)\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.WRONG_WHITESPACE)\n    fun `space after annotation`() {\n        lintMethod(\n            \"\"\"\n                    |@Annotation (\"Text\")\n                    |fun foo() {\n                    |\n                    |}\n            \"\"\".trimMargin(),\n            DiktatError(1, 13, ruleId, tokenWarn(\"(\\\"Text\\\")\", 1, null, 0, null), true)\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.WRONG_WHITESPACE)\n    fun `check space on both sides of equals`() {\n        lintMethod(\n            \"\"\"\n                    |fun foo() {\n                    |   val q=10\n                    |   var w = 10\n                    |   w=q\n                    |}\n            \"\"\".trimMargin(),\n            DiktatError(2, 9, ruleId, tokenWarn(\"=\", 0, 0, 1, 1), true),\n            DiktatError(4, 5, ruleId, tokenWarn(\"=\", 0, 0, 1, 1), true)\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.WRONG_WHITESPACE)\n    fun `check eq in other cases`() {\n        lintMethod(\n            \"\"\"\n                    |fun foo()=10\n                    |\n                    |val q =goo(text=ty)\n            \"\"\".trimMargin(),\n            DiktatError(1, 10, ruleId, tokenWarn(\"=\", 0, 0, 1, 1), true),\n            DiktatError(3, 7, ruleId, tokenWarn(\"=\", null, 0, 1, 1), true),\n            DiktatError(3, 16, ruleId, tokenWarn(\"=\", 0, 0, 1, 1), true)\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.WRONG_WHITESPACE)\n    fun `singe space after open brace`() {\n        lintMethod(\n            \"\"\"\n                    |fun foo() {\n                    |   \"${\"$\"}{foo()}\"\n                    |}\n            \"\"\".trimMargin()\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.WRONG_WHITESPACE)\n    fun `array initializers in annotations`() {\n        lintMethod(\n            \"\"\"\n                    |@RequestMapping(value =[\"/\"], method = [RequestMethod.GET])\n                    |fun foo() {\n                    |   a[0]\n                    |}\n            \"\"\".trimMargin(),\n            DiktatError(1, 23, ruleId, tokenWarn(\"=\", null, 0, 1, 1), true),\n            DiktatError(1, 24, ruleId, tokenWarn(\"[\", 0, null, 1, 0), true)\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.WRONG_WHITESPACE)\n    fun `lambda as rigth value in arguments`() {\n        lintMethod(\n            \"\"\"\n                    |fun foo() {\n                    |   Example(cb = { _, _ -> Unit })\n                    |}\n            \"\"\".trimMargin()\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.WRONG_WHITESPACE)\n    fun `lambdas as argument for function`() {\n        lintMethod(\n            \"\"\"\n                    |val q = foo(bar, { it.baz() })\n                    |val q = foo({ it.baz() })\n                    |val q = foo( { it.baz() })\n            \"\"\".trimMargin(),\n            DiktatError(3, 14, ruleId,\n                \"${WRONG_WHITESPACE.warnText()} there should be no whitespace before '{' of lambda inside argument list\", true)\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.WRONG_WHITESPACE)\n    fun `regression - prefix coloncolon should be checked separately - positive example`() {\n        lintMethod(\n            \"\"\"\n                    |fun foo() {\n                    |    Example(::ClassName)\n                    |    bar(param1, ::ClassName)\n                    |    bar(param1, param2 = ::ClassName)\n                    |    list.map(::operationReference)\n                    |}\n            \"\"\".trimMargin()\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.WRONG_WHITESPACE)\n    fun `regression - prefix coloncolon should be checked separately`() {\n        lintMethod(\n            \"\"\"\n                    |fun foo() {\n                    |    Example( :: ClassName)\n                    |    bar(param1,  :: ClassName)\n                    |    bar(param1, param2 = :: ClassName)\n                    |    list.map(:: operationReference)\n                    |}\n            \"\"\".trimMargin(),\n            DiktatError(2, 12, ruleId, tokenWarn(\"(\", null, 1, 0, 0), true),\n            DiktatError(2, 14, ruleId, tokenWarn(\"::\", null, 1, null, 0), true),\n            DiktatError(3, 15, ruleId, tokenWarn(\",\", null, 2, 0, 1), true),\n            DiktatError(3, 18, ruleId, tokenWarn(\"::\", null, 1, null, 0), true),\n            DiktatError(4, 26, ruleId, tokenWarn(\"::\", null, 1, null, 0), true),\n            DiktatError(5, 14, ruleId, tokenWarn(\"::\", null, 1, null, 0), true)\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.WRONG_WHITESPACE)\n    fun `regression - should correctly handle prefix and postfix operators`() {\n        lintMethod(\n            \"\"\"\n                |fun foo() {\n                |    var index = 1\n                |    --index\n                |    return index++\n                |}\n                |\n                |fun bar() {\n                |    var index = 1\n                |    -- index\n                |    return index ++\n                |}\n            \"\"\".trimMargin(),\n            DiktatError(9, 5, ruleId, tokenWarn(\"--\", null, 1, null, 0), true),\n            DiktatError(10, 18, ruleId, tokenWarn(\"++\", 1, null, 0, null), true)\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.WRONG_WHITESPACE)\n    fun `check whitespaces around braces in lambda example - good`() {\n        lintMethod(\n            \"\"\"\n                |fun foo() {\n                |    list.map { it.text }\n                |}\n            \"\"\".trimMargin()\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.WRONG_WHITESPACE)\n    fun `check whitespaces around braces in lambda example - bad`() {\n        lintMethod(\n            \"\"\"\n                |fun foo() {\n                |    list.map {it.text}\n                |}\n            \"\"\".trimMargin(),\n            DiktatError(2, 14, ruleId, \"${WRONG_WHITESPACE.warnText()} there should be a whitespace after {\", true),\n            DiktatError(2, 22, ruleId, \"${WRONG_WHITESPACE.warnText()} there should be a whitespace before }\", true)\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.WRONG_WHITESPACE)\n    fun `should not trigger on braces with empty body #1`() {\n        lintMethod(\n            \"\"\"\n                |val project = KotlinCoreEnvironment.createForProduction(\n                |   Disposable {},\n                |   compilerConfiguration,\n                |   EnvironmentConfigFiles.JVM_CONFIG_FILES\n                |).project\n            \"\"\".trimMargin()\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.WRONG_WHITESPACE)\n    fun `should not trigger on braces with empty body #2`() {\n        lintMethod(\n            \"\"\"\n                |val project = KotlinCoreEnvironment.createForProduction(\n                |   Disposable { },\n                |   compilerConfiguration,\n                |   EnvironmentConfigFiles.JVM_CONFIG_FILES\n                |).project\n            \"\"\".trimMargin()\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.WRONG_WHITESPACE)\n    fun `should not trigger in braces on the beginning of the line`() {\n        lintMethod(\n            \"\"\"\n                |val onClick: () -> Unit = remember {\n                |    {\n                |        /* do stuff */\n                |    }\n                |}\n            \"\"\".trimMargin()\n        )\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/test/kotlin/com/saveourtool/diktat/ruleset/chapter3/spaces/junit/IndentationTest.kt",
    "content": "package com.saveourtool.diktat.ruleset.chapter3.spaces.junit\n\nimport generated.WarningNames.WRONG_INDENTATION\nimport org.junit.jupiter.api.Tag\nimport org.junit.jupiter.api.TestTemplate\nimport org.junit.jupiter.api.extension.ExtendWith\nimport kotlin.annotation.AnnotationRetention.RUNTIME\nimport kotlin.annotation.AnnotationTarget.FUNCTION\n\n/**\n * @property includeWarnTests whether unit tests for the \"warn\" mode should also\n *   be generated. If `false`, the code is allowed to have no expected-error\n *   annotations, and only fix mode tests get generated. The default is `true`.\n * @property singleConfiguration whether only a single code fragment is to be\n *   analysed. If `true`, the value of [second] is ignored, resulting in fewer\n *   unit tests being generated. The default is `false`.\n */\n@Target(FUNCTION)\n@Retention(RUNTIME)\n@MustBeDocumented\n@TestTemplate\n@ExtendWith(IndentationTestInvocationContextProvider::class)\n@Tag(WRONG_INDENTATION)\nannotation class IndentationTest(\n    val first: IndentedSourceCode,\n    val second: IndentedSourceCode = IndentedSourceCode(\"\"),\n    val includeWarnTests: Boolean = true,\n    val singleConfiguration: Boolean = false,\n)\n"
  },
  {
    "path": "diktat-rules/src/test/kotlin/com/saveourtool/diktat/ruleset/chapter3/spaces/junit/IndentationTestExtension.kt",
    "content": "@file:Suppress(\"FILE_UNORDERED_IMPORTS\")// False positives, see #1494.\n\npackage com.saveourtool.diktat.ruleset.chapter3.spaces.junit\n\nimport com.saveourtool.diktat.ruleset.utils.indentation.IndentationConfig.Companion.NEWLINE_AT_END\nimport org.intellij.lang.annotations.Language\nimport org.junit.jupiter.api.extension.BeforeTestExecutionCallback\nimport com.saveourtool.diktat.ruleset.chapter3.spaces.IndentationConfigFactory as IndentationConfig\n\n/**\n * The common super-interface for indentation-specific `Extension`\n * implementations.\n */\ninternal interface IndentationTestExtension : BeforeTestExecutionCallback {\n    /**\n     * The default configuration for the indentation rule.\n     */\n    @Suppress(\"CUSTOM_GETTERS_SETTERS\")\n    val defaultConfig\n        get() =\n            IndentationConfig(NEWLINE_AT_END to false)\n\n    /**\n     * Non-default configuration for the indentation rule.\n     */\n    val customConfig: Map<String, Any>\n\n    /**\n     * The original file content (may well get modified as fixes are applied).\n     */\n    @get:Language(\"kotlin\")\n    val actualCode: String\n}\n"
  },
  {
    "path": "diktat-rules/src/test/kotlin/com/saveourtool/diktat/ruleset/chapter3/spaces/junit/IndentationTestFixExtension.kt",
    "content": "package com.saveourtool.diktat.ruleset.chapter3.spaces.junit\n\nimport com.saveourtool.diktat.ruleset.chapter3.spaces.asRulesConfigList\nimport com.saveourtool.diktat.ruleset.chapter3.spaces.withCustomParameters\nimport com.saveourtool.diktat.ruleset.junit.CloseablePath\nimport com.saveourtool.diktat.ruleset.rules.chapter3.files.IndentationRule\nimport com.saveourtool.diktat.util.FixTestBase\nimport org.intellij.lang.annotations.Language\nimport org.junit.jupiter.api.extension.BeforeEachCallback\nimport org.junit.jupiter.api.extension.ExtensionContext\nimport org.junit.jupiter.api.extension.ExtensionContext.Namespace\nimport java.nio.file.Path\nimport kotlin.io.path.createTempDirectory\n\n/**\n * The `Extension` implementation for indentation test templates (fix mode).\n *\n * @property customConfig non-default configuration for the indentation rule.\n * @property actualCode the original file content (may well get modified as\n *   fixes are applied).\n */\n@Suppress(\n    \"TOO_MANY_BLANK_LINES\",  // Readability\n    \"WRONG_INDENTATION\")  // False positives, see #1404.\nclass IndentationTestFixExtension(\n    override val customConfig: Map<String, Any>,\n    @Language(\"kotlin\") override val actualCode: String,\n    @Language(\"kotlin\") private val expectedCode: String\n) : FixTestBase(\"nonexistent\", ::IndentationRule),\n    IndentationTestExtension,\n    BeforeEachCallback {\n\n    private lateinit var tempDir: Path\n\n    override fun beforeEach(context: ExtensionContext) {\n        tempDir = context.getStore(namespace).getOrComputeIfAbsent(KEY, {\n            CloseablePath(createTempDirectory(prefix = TEMP_DIR_PREFIX))\n        }, CloseablePath::class.java).directory\n    }\n\n    override fun beforeTestExecution(context: ExtensionContext) {\n        val lintResult = fixAndCompareContent(\n            actualCode,\n            expectedCode,\n            tempDir,\n            overrideRulesConfigList = defaultConfig.withCustomParameters(customConfig).asRulesConfigList(),\n        )\n\n        lintResult.assertSuccessful()\n    }\n\n    private companion object {\n        private const val KEY = \"temp.dir\"\n        private const val TEMP_DIR_PREFIX = \"junit\"\n        private val namespace = Namespace.create(IndentationTestFixExtension::class)\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/test/kotlin/com/saveourtool/diktat/ruleset/chapter3/spaces/junit/IndentationTestFixInvocationContext.kt",
    "content": "package com.saveourtool.diktat.ruleset.chapter3.spaces.junit\n\nimport org.intellij.lang.annotations.Language\nimport org.junit.jupiter.api.extension.Extension\nimport java.util.SortedMap\n\n/**\n * @property customConfig non-default configuration for the indentation rule.\n * @property actualCode the original file content (may well get modified as\n *   fixes are applied).\n * @property expectedCode the content the file is expected to have after the\n *   fixes are applied.\n */\n@Suppress(\"BLANK_LINE_BETWEEN_PROPERTIES\")\nclass IndentationTestFixInvocationContext(\n    override val customConfig: SortedMap<String, out Any>,\n    @Language(\"kotlin\") override val actualCode: String,\n    @Language(\"kotlin\") private val expectedCode: String = actualCode\n) : IndentationTestInvocationContext {\n    override val mode: String = \"fix\"\n\n    override val correctlyIndented: Boolean = actualCode == expectedCode\n\n    override val displayName: String = when {\n        correctlyIndented -> \"should remain unchanged if properly indented\"\n        else -> \"should be reformatted if mis-indented\"\n    }\n\n    override fun getAdditionalExtensions(): List<Extension> =\n        listOf(IndentationTestFixExtension(customConfig, actualCode, expectedCode))\n}\n"
  },
  {
    "path": "diktat-rules/src/test/kotlin/com/saveourtool/diktat/ruleset/chapter3/spaces/junit/IndentationTestInput.kt",
    "content": "@file:Suppress(\"FILE_UNORDERED_IMPORTS\")// False positives, see #1494.\n\npackage com.saveourtool.diktat.ruleset.chapter3.spaces.junit\n\nimport com.saveourtool.diktat.ruleset.chapter3.spaces.ExpectedIndentationError\nimport com.saveourtool.diktat.ruleset.chapter3.spaces.withCustomParameters\nimport com.saveourtool.diktat.ruleset.utils.indentation.IndentationConfig.Companion.NEWLINE_AT_END\nimport org.intellij.lang.annotations.Language\nimport java.util.SortedMap\nimport com.saveourtool.diktat.ruleset.chapter3.spaces.IndentationConfigFactory as IndentationConfig\n\n/**\n * The test data for indentation tests, extracted from annotations.\n *\n * @property code the code to check.\n * @property expectedErrors the expected lint errors (may be empty).\n * @property customConfig non-default configuration for the indentation rule.\n */\ndata class IndentationTestInput(\n    @Language(\"kotlin\") val code: String,\n    val expectedErrors: List<ExpectedIndentationError>,\n    val customConfig: SortedMap<String, out Any>,\n) {\n    /**\n     * The effective configuration for the indentation rule (contains both\n     * default and non-default entries).\n     */\n    @Suppress(\"CUSTOM_GETTERS_SETTERS\")\n    val effectiveConfig: Map<String, String>\n        get() =\n            IndentationConfig(NEWLINE_AT_END to false).withCustomParameters(customConfig)\n}\n"
  },
  {
    "path": "diktat-rules/src/test/kotlin/com/saveourtool/diktat/ruleset/chapter3/spaces/junit/IndentationTestInvocationContext.kt",
    "content": "package com.saveourtool.diktat.ruleset.chapter3.spaces.junit\n\nimport org.intellij.lang.annotations.Language\nimport org.junit.jupiter.api.extension.TestTemplateInvocationContext\nimport java.util.SortedMap\n\n/**\n * The [TestTemplateInvocationContext] implementation for indentation tests.\n */\ninterface IndentationTestInvocationContext : TestTemplateInvocationContext {\n    /**\n     * Non-default configuration for the indentation rule.\n     */\n    val customConfig: SortedMap<String, out Any>\n\n    /**\n     * The original file content (may well get modified as fixes are applied).\n     */\n    @get:Language(\"kotlin\")\n    val actualCode: String\n\n    /**\n     * The mode of this invocation context, either \"warn\" or \"fix\".\n     */\n    val mode: String\n\n    /**\n     * Whether the code in this test is indented in accordance with the\n     * effective configuration.\n     */\n    val correctlyIndented: Boolean\n\n    /**\n     * The detailed display name of this invocation context.\n     */\n    val displayName: String\n\n    override fun getDisplayName(invocationIndex: Int): String {\n        val parameterDescription = when {\n            customConfig.isEmpty() -> invocationIndex\n            else -> customConfig.asParameterList()\n        }\n\n        return \"[$mode] $displayName [$parameterDescription]\"\n    }\n\n    private companion object {\n        private fun Map<*, *>.asParameterList(): String =\n            asSequence().map { (key, value) ->\n                \"$key = $value\"\n            }.joinToString()\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/test/kotlin/com/saveourtool/diktat/ruleset/chapter3/spaces/junit/IndentationTestInvocationContextProvider.kt",
    "content": "package com.saveourtool.diktat.ruleset.chapter3.spaces.junit\n\nimport com.saveourtool.diktat.ruleset.chapter3.spaces.ExpectedIndentationError\nimport com.saveourtool.diktat.ruleset.junit.RuleInvocationContextProvider\nimport com.saveourtool.diktat.ruleset.utils.NEWLINE\nimport com.saveourtool.diktat.ruleset.utils.indentation.IndentationConfig.Companion.EXTENDED_INDENT_AFTER_OPERATORS\nimport com.saveourtool.diktat.ruleset.utils.indentation.IndentationConfig.Companion.EXTENDED_INDENT_BEFORE_DOT\nimport com.saveourtool.diktat.ruleset.utils.indentation.IndentationConfig.Companion.EXTENDED_INDENT_FOR_EXPRESSION_BODIES\nimport com.saveourtool.diktat.ruleset.utils.indentation.IndentationConfig.Companion.EXTENDED_INDENT_OF_PARAMETERS\nimport com.saveourtool.diktat.ruleset.utils.leadingSpaceCount\nimport com.saveourtool.diktat.util.assertNotNull\nimport generated.WarningNames.WRONG_INDENTATION\nimport org.assertj.core.api.Assertions.assertThat\nimport org.assertj.core.api.Assertions.fail\nimport org.intellij.lang.annotations.Language\nimport org.junit.jupiter.api.extension.ExtensionContext\nimport org.junit.jupiter.api.extension.TestTemplateInvocationContext\nimport org.junit.platform.commons.util.AnnotationUtils.findAnnotation\nimport java.util.SortedMap\nimport java.util.stream.Stream\nimport java.util.stream.Stream.concat\nimport kotlin.reflect.KClass\n\n/**\n * The `TestTemplateInvocationContextProvider` implementation for indentation\n * tests.\n */\nclass IndentationTestInvocationContextProvider : RuleInvocationContextProvider<IndentationTest, ExpectedIndentationError> {\n    override fun annotationType(): KClass<IndentationTest> =\n        IndentationTest::class\n\n    override fun expectedLintErrorFrom(\n        @Language(\"kotlin\") line: String,\n        lineNumber: Int,\n        tag: String,\n        properties: Map<String, String?>\n    ): ExpectedIndentationError {\n        val message = properties[MESSAGE]\n        @Suppress(\"AVOID_NULL_CHECKS\")\n        if (message != null) {\n            return ExpectedIndentationError(\n                line = lineNumber,\n                message = \"[$WRONG_INDENTATION] $message\")\n        }\n\n        val expectedIndent = properties.expectedIndent()\n        val actualIndent = line.leadingSpaceCount()\n\n        assertThat(actualIndent)\n            .describedAs(\"Expected and actual indent values are the same: $expectedIndent, line $lineNumber (\\\"$line\\\")\")\n            .isNotEqualTo(expectedIndent)\n\n        assertThat(tag)\n            .describedAs(\"Unexpected tag: $tag\")\n            .isEqualTo(WRONG_INDENTATION)\n\n        return ExpectedIndentationError(\n            line = lineNumber,\n            expectedIndent = expectedIndent,\n            actualIndent = actualIndent)\n    }\n\n    @Suppress(\"TOO_LONG_FUNCTION\")\n    override fun provideTestTemplateInvocationContexts(context: ExtensionContext, supportedTags: List<String>): Stream<TestTemplateInvocationContext> {\n        val testMethod = context.requiredTestMethod\n\n        val indentationTest = findAnnotation(testMethod, annotationType().java).get()\n\n        val includeWarnTests = indentationTest.includeWarnTests\n        val singleConfiguration = indentationTest.singleConfiguration\n\n        val testInput0 = indentationTest.first.extractTestInput(\n            supportedTags,\n            allowEmptyErrors = !includeWarnTests || singleConfiguration)\n        val (code0, expectedErrors0, customConfig0) = testInput0\n\n        var contexts: Stream<TestTemplateInvocationContext> = Stream.of(\n            IndentationTestFixInvocationContext(customConfig0, actualCode = code0)\n        )\n\n        if (includeWarnTests) {\n            /*-\n             * In a double-configuration mode (the default), when the code is\n             * checked against its own configuration, the actual list of errors\n             * is expected to be empty (it's only used when the code is checked\n             * against the opposite configuration.\n             *\n             * In a single-configuration mode, the opposite configuration is\n             * empty, so let's allow a non-empty list of expected errors when\n             * the code is checked against its own configuration.\n             */\n            val expectedErrors = when {\n                singleConfiguration -> expectedErrors0\n                else -> emptyList()\n            }\n            contexts += IndentationTestWarnInvocationContext(customConfig0, actualCode = code0, expectedErrors)\n        }\n\n        when {\n            singleConfiguration -> {\n                val code1 = indentationTest.second.code\n                assertThat(code1)\n                    .describedAs(\"The 2nd code fragment should be empty if `singleConfiguration` is `true`: $NEWLINE$code1\")\n                    .isEmpty()\n            }\n\n            else -> {\n                val testInput1 = indentationTest.second.extractTestInput(\n                    supportedTags,\n                    allowEmptyErrors = !includeWarnTests)\n                val (code1, expectedErrors1, customConfig1) = testInput1\n\n                assertThat(code0)\n                    .describedAs(\"Both code fragments are the same\")\n                    .isNotEqualTo(code1)\n                assertThat(customConfig0)\n                    .describedAs(\"Both custom configs are the same\")\n                    .isNotEqualTo(customConfig1)\n                assertThat(testInput0.effectiveConfig)\n                    .describedAs(\"Both effective configs are the same\")\n                    .isNotEqualTo(testInput1.effectiveConfig)\n\n                contexts += IndentationTestFixInvocationContext(customConfig1, actualCode = code1)\n                contexts += IndentationTestFixInvocationContext(customConfig1, actualCode = code0, expectedCode = code1)\n                contexts += IndentationTestFixInvocationContext(customConfig0, actualCode = code1, expectedCode = code0)\n\n                if (includeWarnTests) {\n                    contexts += IndentationTestWarnInvocationContext(customConfig1, actualCode = code1)\n                    contexts += IndentationTestWarnInvocationContext(customConfig1, actualCode = code0, expectedErrors0)\n                    contexts += IndentationTestWarnInvocationContext(customConfig0, actualCode = code1, expectedErrors1)\n                }\n            }\n        }\n\n        return contexts.sorted { left, right ->\n            left.getDisplayName(0).compareTo(right.getDisplayName(0))\n        }\n    }\n\n    /**\n     * @param allowEmptyErrors whether the list of expected errors is allowed to\n     *   be empty (i.e. the code may contain no known annotations).\n     */\n    private fun IndentedSourceCode.extractTestInput(supportedTags: List<String>,\n                                                    allowEmptyErrors: Boolean): IndentationTestInput {\n        val (code, expectedErrors) = extractExpectedErrors(code, supportedTags, allowEmptyErrors)\n\n        return IndentationTestInput(code, expectedErrors, customConfig())\n    }\n\n    private companion object {\n        private const val EXPECTED_INDENT = \"expectedIndent\"\n        private const val MESSAGE = \"message\"\n\n        @Suppress(\"WRONG_NEWLINES\")  // False positives, see #1495.\n        private fun IndentedSourceCode.customConfig(): SortedMap<String, out Boolean> =\n            mapOf(\n                EXTENDED_INDENT_AFTER_OPERATORS to extendedIndentAfterOperators,\n                EXTENDED_INDENT_BEFORE_DOT to extendedIndentBeforeDot,\n                EXTENDED_INDENT_FOR_EXPRESSION_BODIES to extendedIndentForExpressionBodies,\n                EXTENDED_INDENT_OF_PARAMETERS to extendedIndentOfParameters,\n            ).mapValues { (_, value) ->\n                value.valueOrNull\n            }.filterValues { value ->\n                value != null\n            }.mapValues { (_, value) ->\n                value!!\n            }.toSortedMap()\n\n        private fun Map<String, String?>.expectedIndent(): Int {\n            val expectedIndentRaw = this[EXPECTED_INDENT].assertNotNull {\n                \"There's no `$EXPECTED_INDENT` key in $this\"\n            }\n\n            assertThat(expectedIndentRaw)\n                .describedAs(\"`$EXPECTED_INDENT` is empty\")\n                .isNotEmpty\n\n            return try {\n                expectedIndentRaw.toInt()\n            } catch (_: NumberFormatException) {\n                fail(\"Unparseable `$EXPECTED_INDENT`: $expectedIndentRaw\")\n            }\n        }\n\n        private operator fun <T> Stream<T>.plus(value: T): Stream<T> =\n            concat(this, Stream.of(value))\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/test/kotlin/com/saveourtool/diktat/ruleset/chapter3/spaces/junit/IndentationTestWarnExtension.kt",
    "content": "package com.saveourtool.diktat.ruleset.chapter3.spaces.junit\n\nimport com.saveourtool.diktat.ruleset.chapter3.spaces.asRulesConfigList\nimport com.saveourtool.diktat.ruleset.chapter3.spaces.withCustomParameters\nimport com.saveourtool.diktat.ruleset.rules.chapter3.files.IndentationRule\nimport com.saveourtool.diktat.ruleset.utils.NEWLINE\nimport com.saveourtool.diktat.util.LintTestBase\nimport com.saveourtool.diktat.api.DiktatError\nimport org.assertj.core.api.Assertions.assertThat\nimport org.intellij.lang.annotations.Language\nimport org.junit.jupiter.api.extension.ExtensionContext\nimport kotlin.math.max\nimport kotlin.math.min\n\n/**\n * The `Extension` implementation for indentation test templates (warn mode).\n *\n * @property customConfig non-default configuration for the indentation rule.\n * @property actualCode the original file content (may well get modified as\n *   fixes are applied).\n */\n@Suppress(\"TOO_MANY_BLANK_LINES\")  // Readability\ninternal class IndentationTestWarnExtension(\n    override val customConfig: Map<String, Any>,\n    @Language(\"kotlin\") override val actualCode: String,\n    private val expectedErrors: Array<DiktatError>\n) : LintTestBase(::IndentationRule), IndentationTestExtension {\n\n    override fun beforeTestExecution(context: ExtensionContext) {\n        val actualErrors = lintResult(\n            actualCode,\n            defaultConfig.withCustomParameters(customConfig).asRulesConfigList())\n\n        val description = NEWLINE + actualCode.annotateWith(actualErrors) + NEWLINE\n\n        when {\n            expectedErrors.size == 1 && actualErrors.size == 1 -> {\n                val actual = actualErrors[0]\n                val expected = expectedErrors[0]\n\n                assertThat(actual)\n                    .describedAs(description)\n                    .isEqualTo(expected)\n                assertThat(actual.canBeAutoCorrected)\n                    .describedAs(\"canBeAutoCorrected\")\n                    .isEqualTo(expected.canBeAutoCorrected)\n            }\n\n            else -> assertThat(actualErrors)\n                .describedAs(description)\n                .apply {\n                    when {\n                        expectedErrors.isEmpty() -> isEmpty()\n                        else -> containsExactly(*expectedErrors)\n                    }\n                }\n        }\n    }\n\n    private companion object {\n        /**\n         * Converts a lint error to the annotation text:\n         *\n         * ```\n         * ^____^\n         * ```\n         *\n         * allowing in-code annotations like\n         *\n         * ```\n         * fun f() {\n         *     1 +\n         *                                  2\n         *         ^________________________^\n         * ```\n         */\n        @Suppress(\"CUSTOM_GETTERS_SETTERS\")\n        private val DiktatError.annotationText: String\n            get() {\n                @Suppress(\"WRONG_NEWLINES\")  // False positives, see #1495.\n                val columnNumbers = decimalNumber\n                    .findAll(detail)\n                    .map { match ->\n                        match.groups[1]?.value\n                    }.filterNotNull()\n                    .map(String::toInt)\n                    .toList()\n                    .takeLast(2)\n\n                return when (columnNumbers.size) {\n                    2 -> sequence {\n                        yield(NEWLINE)\n\n                        val columnNumber0 = columnNumbers[0]\n                        val columnNumber1 = columnNumbers[1]\n                        for (columnNumber in 1..max(columnNumber0, columnNumber1) + 1) {\n                            val ch = when {\n                                columnNumber <= min(columnNumber0, columnNumber1) -> ' '\n                                columnNumber == columnNumber0 + 1 || columnNumber == columnNumber1 + 1 -> '^'\n                                else -> '_'\n                            }\n                            yield(ch)\n                        }\n                    }.joinToString(separator = \"\")\n                    else -> \"\"\n                }\n            }\n\n        private val decimalNumber = Regex(\"\"\"\\b[+-]?(\\d++)\\b\"\"\")\n\n        private fun String.annotateWith(errors: List<DiktatError>): String =\n            when {\n                errors.isEmpty() -> this\n                else -> {\n                    val linesAndErrors = errors.asSequence().map { error -> error.line to error }.toMap()\n\n                    lineSequence().mapIndexed { index, line ->\n                        when (val error = linesAndErrors[index + 1]) {\n                            null -> line\n                            else -> \"$line${error.annotationText}\"\n                        }\n                    }.joinToString(separator = NEWLINE.toString())\n                }\n            }\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/test/kotlin/com/saveourtool/diktat/ruleset/chapter3/spaces/junit/IndentationTestWarnInvocationContext.kt",
    "content": "package com.saveourtool.diktat.ruleset.chapter3.spaces.junit\n\nimport com.saveourtool.diktat.ruleset.chapter3.spaces.ExpectedIndentationError\nimport com.saveourtool.diktat.ruleset.junit.ExpectedLintError\nimport org.intellij.lang.annotations.Language\nimport org.junit.jupiter.api.extension.Extension\nimport java.util.SortedMap\n\n/**\n * The `TestTemplateInvocationContext` implementation for indentation tests\n * (warn mode).\n *\n * @property customConfig non-default configuration for the indentation rule.\n * @property actualCode the original file content (may well get modified as\n *   fixes are applied).\n */\n@Suppress(\"BLANK_LINE_BETWEEN_PROPERTIES\")\ninternal class IndentationTestWarnInvocationContext(\n    override val customConfig: SortedMap<String, out Any>,\n    @Language(\"kotlin\") override val actualCode: String,\n    private val expectedErrors: List<ExpectedIndentationError> = emptyList()\n) : IndentationTestInvocationContext {\n    override val mode: String = \"warn\"\n\n    override val correctlyIndented: Boolean = expectedErrors.isEmpty()\n\n    override val displayName: String = when {\n        correctlyIndented -> \"should raise no warnings if properly indented\"\n        else -> \"should be reported if mis-indented\"\n    }\n\n    override fun getAdditionalExtensions(): List<Extension> =\n        listOf(IndentationTestWarnExtension(\n            customConfig,\n            actualCode,\n            expectedErrors.map(ExpectedLintError::asLintError).toTypedArray()))\n}\n"
  },
  {
    "path": "diktat-rules/src/test/kotlin/com/saveourtool/diktat/ruleset/chapter3/spaces/junit/IndentedSourceCode.kt",
    "content": "package com.saveourtool.diktat.ruleset.chapter3.spaces.junit\n\nimport com.saveourtool.diktat.ruleset.junit.BooleanOrDefault\nimport com.saveourtool.diktat.ruleset.junit.BooleanOrDefault.DEFAULT\nimport org.intellij.lang.annotations.Language\nimport kotlin.annotation.AnnotationRetention.RUNTIME\n\n/**\n * Requirements for [code]:\n *\n * - the code should contain at least one expected-error annotation in the\n *   format `diktat:<CHECK_NAME>` or `diktat:<CHECK_NAME>[name1 = value1, name2 = value2]`;\n * - the exact format is `diktat:WRONG_INDENTATION[expectedIndent = <expected indent>]`;\n * - the `expectedIndent` property should be present and its value should be a\n *   number;\n * - the values of expected and actual indent (inferred from the code) should be\n *   different;\n * - the code should be non-blank.\n *\n * @property code the source code to test. Common indentation will be trimmed using\n *   [String.trimIndent].\n * @property extendedIndentOfParameters describes the effective formatting of [code].\n * @property extendedIndentForExpressionBodies describes the effective formatting of [code].\n * @property extendedIndentAfterOperators describes the effective formatting of [code].\n * @property extendedIndentBeforeDot describes the effective formatting of [code].\n */\n@Target\n@Retention(RUNTIME)\n@MustBeDocumented\nannotation class IndentedSourceCode(\n    @Language(\"kotlin\") val code: String,\n    val extendedIndentOfParameters: BooleanOrDefault = DEFAULT,\n    val extendedIndentForExpressionBodies: BooleanOrDefault = DEFAULT,\n    val extendedIndentAfterOperators: BooleanOrDefault = DEFAULT,\n    val extendedIndentBeforeDot: BooleanOrDefault = DEFAULT,\n)\n"
  },
  {
    "path": "diktat-rules/src/test/kotlin/com/saveourtool/diktat/ruleset/chapter4/AccurateCalculationsWarnTest.kt",
    "content": "package com.saveourtool.diktat.ruleset.chapter4\n\nimport com.saveourtool.diktat.common.config.rules.DIKTAT_RULE_SET_ID\nimport com.saveourtool.diktat.ruleset.constants.Warnings.FLOAT_IN_ACCURATE_CALCULATIONS\nimport com.saveourtool.diktat.ruleset.rules.chapter4.calculations.AccurateCalculationsRule\nimport com.saveourtool.diktat.util.LintTestBase\n\nimport com.saveourtool.diktat.api.DiktatError\nimport generated.WarningNames\nimport org.junit.jupiter.api.Tag\nimport org.junit.jupiter.api.Test\n\nclass AccurateCalculationsWarnTest : LintTestBase(::AccurateCalculationsRule) {\n    private val ruleId = \"$DIKTAT_RULE_SET_ID:${AccurateCalculationsRule.NAME_ID}\"\n\n    private fun warnText(ref: String, expr: String) = \"${FLOAT_IN_ACCURATE_CALCULATIONS.warnText()} float value of <$ref> used in arithmetic expression in $expr\"\n\n    @Test\n    @Tag(WarningNames.FLOAT_IN_ACCURATE_CALCULATIONS)\n    fun `should detect comparison (equals) with float literal`() {\n        lintMethod(\n            \"\"\"\n                    |class Example {\n                    |    fun foo() {\n                    |        x == 1.0\n                    |        1.0 == x\n                    |        x.equals(1.0)\n                    |        1.0.equals(x)\n                    |    }\n                    |}\n            \"\"\".trimMargin(),\n            DiktatError(3, 9, ruleId, warnText(\"1.0\", \"x == 1.0\"), false),\n            DiktatError(4, 9, ruleId, warnText(\"1.0\", \"1.0 == x\"), false),\n            DiktatError(5, 9, ruleId, warnText(\"1.0\", \"x.equals(1.0)\"), false),\n            DiktatError(6, 9, ruleId, warnText(\"1.0\", \"1.0.equals(x)\"), false)\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.FLOAT_IN_ACCURATE_CALCULATIONS)\n    fun `should detect comparison with float literal`() {\n        lintMethod(\n            \"\"\"\n                    |class Example {\n                    |    fun foo() {\n                    |        x > 1.0\n                    |        1.0 > x\n                    |        x.compareTo(1.0)\n                    |        1.0.compareTo(x)\n                    |    }\n                    |}\n            \"\"\".trimMargin(),\n            DiktatError(3, 9, ruleId, warnText(\"1.0\", \"x > 1.0\"), false),\n            DiktatError(4, 9, ruleId, warnText(\"1.0\", \"1.0 > x\"), false),\n            DiktatError(5, 9, ruleId, warnText(\"1.0\", \"x.compareTo(1.0)\"), false),\n            DiktatError(6, 9, ruleId, warnText(\"1.0\", \"1.0.compareTo(x)\"), false)\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.FLOAT_IN_ACCURATE_CALCULATIONS)\n    fun `should detect comparisons with local floating-point variables - 1`() {\n        lintMethod(\n            \"\"\"\n                    |class Example {\n                    |    fun foo() {\n                    |        val x = 1.0\n                    |        x == 1\n                    |    }\n                    |}\n            \"\"\".trimMargin(),\n            DiktatError(4, 9, ruleId, warnText(\"x\", \"x == 1\"), false)\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.FLOAT_IN_ACCURATE_CALCULATIONS)\n    fun `should detect comparisons with local floating-point variables - 2`() {\n        lintMethod(\n            \"\"\"\n                    |class Example {\n                    |    fun foo() {\n                    |        val x = 1L\n                    |        list.forEach {\n                    |            val x = 1.0\n                    |            x == 1\n                    |        }\n                    |    }\n                    |}\n            \"\"\".trimMargin(),\n            DiktatError(6, 13, ruleId, warnText(\"x\", \"x == 1\"), false)\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.FLOAT_IN_ACCURATE_CALCULATIONS)\n    fun `should detect comparisons with local floating-point variables - 3`() {\n        lintMethod(\n            \"\"\"\n                    |class Example {\n                    |    fun foo() {\n                    |        val x = 1L\n                    |        list.forEach {\n                    |            obj.let {\n                    |                x == 1\n                    |            }\n                    |            val x = 1.0\n                    |        }\n                    |    }\n                    |}\n            \"\"\".trimMargin()\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.FLOAT_IN_ACCURATE_CALCULATIONS)\n    fun `should detect different operations with operators`() {\n        lintMethod(\n            \"\"\"\n                    |class Example {\n                    |    fun foo() {\n                    |        val x = 1.0\n                    |        x == 1\n                    |        x + 2\n                    |        // x++\n                    |        x += 2\n                    |        x - 2\n                    |        // x--\n                    |        x -= 2\n                    |        x * 2\n                    |        x *= 2\n                    |        x / 2\n                    |        x /= 2\n                    |        x % 2\n                    |        x %= 2\n                    |    }\n                    |}\n            \"\"\".trimMargin(),\n            DiktatError(4, 9, ruleId, warnText(\"x\", \"x == 1\"), false),\n            DiktatError(5, 9, ruleId, warnText(\"x\", \"x + 2\"), false),\n            // DiktatError(6, 9, ruleId, warnText(\"x\", \"x++\"), false),\n            DiktatError(7, 9, ruleId, warnText(\"x\", \"x += 2\"), false),\n            DiktatError(8, 9, ruleId, warnText(\"x\", \"x - 2\"), false),\n            // DiktatError(9, 9, ruleId, warnText(\"x\", \"x--\"), false),\n            DiktatError(10, 9, ruleId, warnText(\"x\", \"x -= 2\"), false),\n            DiktatError(11, 9, ruleId, warnText(\"x\", \"x * 2\"), false),\n            DiktatError(12, 9, ruleId, warnText(\"x\", \"x *= 2\"), false),\n            DiktatError(13, 9, ruleId, warnText(\"x\", \"x / 2\"), false),\n            DiktatError(14, 9, ruleId, warnText(\"x\", \"x /= 2\"), false),\n            DiktatError(15, 9, ruleId, warnText(\"x\", \"x % 2\"), false),\n            DiktatError(16, 9, ruleId, warnText(\"x\", \"x %= 2\"), false)\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.FLOAT_IN_ACCURATE_CALCULATIONS)\n    fun `should allow arithmetic operations inside abs in comparison`() {\n        lintMethod(\n            \"\"\"\n                    |import kotlin.math.abs\n                    |\n                    |fun foo() {\n                    |    if (abs(1.0 - 0.999) < 1e-6) {\n                    |        println(\"Comparison with tolerance\")\n                    |    }\n                    |\n                    |    1e-6 > abs(1.0 - 0.999)\n                    |    abs(1.0 - 0.999).compareTo(1e-6) < 0\n                    |    1e-6.compareTo(abs(1.0 - 0.999)) < 0\n                    |    abs(1.0 - 0.999) == 1e-6\n                    |\n                    |    abs(1.0 - 0.999) < eps\n                    |    eps > abs(1.0 - 0.999)\n                    |\n                    |    val x = 1.0\n                    |    val y = 0.999\n                    |    abs(x - y) < eps\n                    |    eps > abs(x - y)\n                    |    abs(1.0 - 0.999) == eps\n                    |}\n            \"\"\".trimMargin(),\n            DiktatError(11, 5, ruleId, warnText(\"1e-6\", \"abs(1.0 - 0.999) == 1e-6\"), false),\n            DiktatError(11, 9, ruleId, warnText(\"1.0\", \"1.0 - 0.999\"), false),\n            DiktatError(20, 9, ruleId, warnText(\"1.0\", \"1.0 - 0.999\"), false)\n        )\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/test/kotlin/com/saveourtool/diktat/ruleset/chapter4/NoVarRuleWarnTest.kt",
    "content": "package com.saveourtool.diktat.ruleset.chapter4\n\nimport com.saveourtool.diktat.common.config.rules.DIKTAT_RULE_SET_ID\nimport com.saveourtool.diktat.ruleset.constants.Warnings\nimport com.saveourtool.diktat.ruleset.rules.chapter4.ImmutableValNoVarRule\nimport com.saveourtool.diktat.util.LintTestBase\n\nimport com.saveourtool.diktat.api.DiktatError\nimport generated.WarningNames.SAY_NO_TO_VAR\nimport org.junit.jupiter.api.Tag\nimport org.junit.jupiter.api.Test\n\nclass NoVarRuleWarnTest : LintTestBase(::ImmutableValNoVarRule) {\n    private val ruleId = \"$DIKTAT_RULE_SET_ID:${ImmutableValNoVarRule.NAME_ID}\"\n\n    @Test\n    @Tag(SAY_NO_TO_VAR)\n    fun `valid case where x is used in while loop as some counter`() {\n        lintMethod(\n            \"\"\"\n                    | fun foo() {\n                    |     var x = 0\n                    |     while (x < 10) {\n                    |        x++\n                    |     }\n                    | }\n            \"\"\".trimMargin(),\n        )\n    }\n\n    @Test\n    @Tag(SAY_NO_TO_VAR)\n    fun `valid case where y is used in for each loop as some counter, but a is not`() {\n        lintMethod(\n            \"\"\"\n                    | fun foo() {\n                    |     var a = emptyList()\n                    |     a = 15\n                    |     var y = 0\n                    |     a.forEach { x ->\n                    |        y = x + 1\n                    |     }\n                    | }\n            \"\"\".trimMargin(),\n            DiktatError(2, 6, ruleId, \"${Warnings.SAY_NO_TO_VAR.warnText()} var a = emptyList()\", false)\n        )\n    }\n\n    @Test\n    @Tag(SAY_NO_TO_VAR)\n    fun `For loop with internal counter`() {\n        lintMethod(\n            \"\"\"\n                    | fun foo() {\n                    |     for (x in 0..10) println(x)\n                    | }\n            \"\"\".trimMargin()\n        )\n    }\n\n    @Test\n    @Tag(SAY_NO_TO_VAR)\n    fun `var in class`() {\n        lintMethod(\n            \"\"\"\n                    | class A {\n                    |     var a = 0\n                    | }\n            \"\"\".trimMargin()\n        )\n    }\n\n    @Test\n    @Tag(SAY_NO_TO_VAR)\n    fun `var used simply in function`() {\n        lintMethod(\n            \"\"\"\n                    | fun foo(): Int {\n                    |     var a = 0\n                    |     a = a + 15\n                    |     a = a + 56\n                    |     return a\n                    | }\n            \"\"\".trimMargin(),\n            DiktatError(2, 6, ruleId, \"${Warnings.SAY_NO_TO_VAR.warnText()} var a = 0\", false)\n        )\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/test/kotlin/com/saveourtool/diktat/ruleset/chapter4/NullChecksRuleFixTest.kt",
    "content": "package com.saveourtool.diktat.ruleset.chapter4\n\nimport com.saveourtool.diktat.ruleset.rules.chapter4.NullChecksRule\nimport com.saveourtool.diktat.util.FixTestBase\n\nimport generated.WarningNames\nimport org.junit.jupiter.api.Tag\nimport org.junit.jupiter.api.Test\n\nclass NullChecksRuleFixTest : FixTestBase(\"test/paragraph4/null_checks\", ::NullChecksRule) {\n    @Test\n    @Tag(WarningNames.AVOID_NULL_CHECKS)\n    fun `should careful fix if conditions with break`() {\n        fixAndCompare(\"IfConditionBreakCheckExpected.kt\", \"IfConditionBreakCheckTest.kt\")\n    }\n\n    @Test\n    @Tag(WarningNames.AVOID_NULL_CHECKS)\n    fun `should fix if conditions`() {\n        fixAndCompare(\"IfConditionNullCheckExpected.kt\", \"IfConditionNullCheckTest.kt\")\n    }\n\n    @Test\n    @Tag(WarningNames.AVOID_NULL_CHECKS)\n    fun `should fix require function`() {\n        fixAndCompare(\"RequireFunctionExpected.kt\", \"RequireFunctionTest.kt\")\n    }\n\n    @Test\n    @Tag(WarningNames.AVOID_NULL_CHECKS)\n    fun `should fix if conditions when assigned`() {\n        fixAndCompare(\"IfConditionAssignCheckExpected.kt\", \"IfConditionAssignCheckTest.kt\")\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/test/kotlin/com/saveourtool/diktat/ruleset/chapter4/NullChecksRuleWarnTest.kt",
    "content": "package com.saveourtool.diktat.ruleset.chapter4\n\nimport com.saveourtool.diktat.common.config.rules.DIKTAT_RULE_SET_ID\nimport com.saveourtool.diktat.ruleset.constants.Warnings\nimport com.saveourtool.diktat.ruleset.rules.chapter4.NullChecksRule\nimport com.saveourtool.diktat.util.LintTestBase\n\nimport com.saveourtool.diktat.api.DiktatError\nimport generated.WarningNames\nimport org.junit.jupiter.api.Tag\nimport org.junit.jupiter.api.Test\n\nclass NullChecksRuleWarnTest : LintTestBase(::NullChecksRule) {\n    private val ruleId = \"$DIKTAT_RULE_SET_ID:${NullChecksRule.NAME_ID}\"\n\n    @Test\n    @Tag(WarningNames.AVOID_NULL_CHECKS)\n    fun `equals to null`() {\n        lintMethod(\n            \"\"\"\n                | fun foo() {\n                |     var myVar: Int? = null\n                |     if (myVar == null) {\n                |         println(\"null\")\n                |         return\n                |     }\n                | }\n            \"\"\".trimMargin(),\n            DiktatError(3, 10, ruleId, \"${Warnings.AVOID_NULL_CHECKS.warnText()} use '.let/.also/?:/e.t.c' instead of myVar == null\", true),\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.AVOID_NULL_CHECKS)\n    fun `equals to null in a chain of binary expressions`() {\n        lintMethod(\n            \"\"\"\n                | fun foo() {\n                |     var myVar: Int? = null\n                |     if ((myVar == null) && (true) || isValid) {\n                |         println(\"null\")\n                |         return\n                |     }\n                |     myVar ?: kotlin.run {\n                |       println(\"null\")\n                |     }\n                | }\n            \"\"\".trimMargin(),\n            DiktatError(3, 11, ruleId, Warnings.AVOID_NULL_CHECKS.warnText() +\n                    \" use '.let/.also/?:/e.t.c' instead of myVar == null\", true),\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.AVOID_NULL_CHECKS)\n    fun `not equals to null`() {\n        lintMethod(\n            \"\"\"\n                | fun foo() {\n                |     if (myVar != null) {\n                |         println(\"not null\")\n                |         return\n                |     }\n                | }\n            \"\"\".trimMargin(),\n            DiktatError(2, 10, ruleId, Warnings.AVOID_NULL_CHECKS.warnText() +\n                    \" use '.let/.also/?:/e.t.c' instead of myVar != null\", true),\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.AVOID_NULL_CHECKS)\n    fun `if-else null comparison with return value`() {\n        lintMethod(\n            \"\"\"\n                | fun foo() {\n                |     val anotherVal = if (myVar != null) {\n                |                          println(\"not null\")\n                |                           1\n                |                      } else {\n                |                           2\n                |                      }\n                | }\n            \"\"\".trimMargin(),\n            DiktatError(2, 27, ruleId, Warnings.AVOID_NULL_CHECKS.warnText() +\n                    \" use '.let/.also/?:/e.t.c' instead of myVar != null\", true),\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.AVOID_NULL_CHECKS)\n    fun `if-else null comparison with no return value`() {\n        lintMethod(\n            \"\"\"\n                | fun foo() {\n                |     if (myVar !== null) {\n                |            println(\"not null\")\n                |     } else {\n                |            println(\"null\")\n                |     }\n                | }\n            \"\"\".trimMargin(),\n            DiktatError(2, 10, ruleId, Warnings.AVOID_NULL_CHECKS.warnText() +\n                    \" use '.let/.also/?:/e.t.c' instead of myVar !== null\", true),\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.AVOID_NULL_CHECKS)\n    fun `equals to null, but not in if`() {\n        lintMethod(\n            \"\"\"\n                | fun foo0() {\n                |     if (true) {\n                |         fun foo() {\n                |             var myVar: Int? = null\n                |             val myVal = myVar == null\n                |             foo1(myVar == null)\n                |             println(\"null\")\n                |         }\n                |      }\n                | }\n            \"\"\".trimMargin(),\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.AVOID_NULL_CHECKS)\n    fun `equals to null, but in complex else-if statement`() {\n        lintMethod(\n            \"\"\"\n                | fun foo0() {\n                |     if (myVar != null) {\n                |        println(\"not null\")\n                |      } else if (true) {\n                |        println()\n                |      }\n                | }\n            \"\"\".trimMargin()\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.AVOID_NULL_CHECKS)\n    fun `equals to null, but in complex else-if statement with dummy comment`() {\n        lintMethod(\n            \"\"\"\n                | fun foo0() {\n                |     if (myVar != null) {\n                |        println(\"not null\")\n                |      } else /* test comment */ if (true) {\n                |        println()\n                |      }\n                | }\n            \"\"\".trimMargin()\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.AVOID_NULL_CHECKS)\n    fun `equals to null, but the expression is not a else-if`() {\n        lintMethod(\n            \"\"\"\n                | fun foo0() {\n                |     if (myVar != null) {\n                |        println(\"not null\")\n                |      } else {\n                |           if (true) {\n                |                println()\n                |           }\n                |      }\n                | }\n            \"\"\".trimMargin(),\n            DiktatError(2, 10, ruleId, \"${Warnings.AVOID_NULL_CHECKS.warnText()} use '.let/.also/?:/e.t.c'\" +\n                    \" instead of myVar != null\", true),\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.AVOID_NULL_CHECKS)\n    fun `require statements - adding `() {\n        lintMethod(\n            \"\"\"\n                | fun foo0(myVar: String?) {\n                |     require(myVar != null)\n                | }\n            \"\"\".trimMargin(),\n            DiktatError(2, 14, ruleId, Warnings.AVOID_NULL_CHECKS.warnText() +\n                    \" use 'requireNotNull' instead of require(myVar != null)\", true),\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.AVOID_NULL_CHECKS)\n    fun `null check in lambda which is in if-statement is ok`() {\n        lintMethod(\n            \"\"\"\n                |fun foo() {\n                |    if (leftSide?.any { it == null } == true) {\n                |        return\n                |    }\n                |}\n            \"\"\".trimMargin()\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.AVOID_NULL_CHECKS)\n    fun `null check in lambda which is in require is ok`() {\n        lintMethod(\n            \"\"\"\n                |fun foo() {\n                |    require(leftSide?.any { it == null })\n                |}\n            \"\"\".trimMargin()\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.AVOID_NULL_CHECKS)\n    fun `don't trigger inside 'init' block when more than one statement in 'else' block`() {\n        lintMethod(\n            \"\"\"\n                |class Demo {\n                |    val one: Int\n                |    val two: String\n                |\n                |    init {\n                |        val number = get()\n                |        if (number != null) {\n                |            one = number.toInt()\n                |            two = number\n                |        } else {\n                |            one = 0\n                |            two = \"0\"\n                |        }\n                |    }\n                |\n                |    private fun get(): String? = if (Math.random() > 0.5) { \"1\" } else { null }\n                |}\n            \"\"\".trimMargin()\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.AVOID_NULL_CHECKS)\n    fun `trigger inside 'init' block when only one statement in 'else' block`() {\n        lintMethod(\n            \"\"\"\n                |class Demo {\n                |    val one: Int = 0\n                |    val two: String = \"\"\n                |\n                |    init {\n                |        val number = get()\n                |        if (number != null) {\n                |            print(number + 1)\n                |        } else {\n                |            print(null)\n                |        }\n                |    }\n                |\n                |    private fun get(): String? = if (Math.random() > 0.5) { \"1\" } else { null }\n                |}\n            \"\"\".trimMargin(),\n            DiktatError(7, 13, ruleId, Warnings.AVOID_NULL_CHECKS.warnText() +\n                    \" use '.let/.also/?:/e.t.c' instead of number != null\", true),\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.AVOID_NULL_CHECKS)\n    fun `trigger inside 'init' block when no 'else' block`() {\n        lintMethod(\n            \"\"\"\n                |class Demo {\n                |    val one: Int = 0\n                |    val two: String = \"\"\n                |\n                |    init {\n                |        val number = get()\n                |        if (number != null) {\n                |            print(number)\n                |        }\n                |    }\n                |\n                |    private fun get(): String? = if (Math.random() > 0.5) { \"1\" } else { null }\n                |}\n            \"\"\".trimMargin(),\n            DiktatError(7, 13, ruleId, Warnings.AVOID_NULL_CHECKS.warnText() +\n                    \" use '.let/.also/?:/e.t.c' instead of number != null\", true),\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.AVOID_NULL_CHECKS)\n    fun `don't trigger inside 'run', 'with', 'apply' scope functions when more than one statement in 'else' block`() {\n        lintMethod(\n            \"\"\"\n                |class Demo {\n                |\n                |    private fun set() {\n                |        val one: Int\n                |        val two: String\n                |\n                |        run {\n                |            val number: String? = get()\n                |            if (number != null) {\n                |                one = number.toInt()\n                |                two = number\n                |            } else {\n                |                one = 0\n                |                two = \"0\"\n                |            }\n                |        }\n                |    }\n                |\n                |    private fun get(): String? = if (Math.random() > 0.5) { \"1\" } else { null }\n                |}\n            \"\"\".trimMargin()\n        )\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/test/kotlin/com/saveourtool/diktat/ruleset/chapter4/SmartCastRuleFixTest.kt",
    "content": "package com.saveourtool.diktat.ruleset.chapter4\n\nimport com.saveourtool.diktat.ruleset.rules.chapter4.SmartCastRule\nimport com.saveourtool.diktat.util.FixTestBase\n\nimport org.junit.jupiter.api.Test\n\nclass SmartCastRuleFixTest : FixTestBase(\"test/paragraph4/smart_cast\", ::SmartCastRule) {\n    @Test\n    fun `should fix enum order`() {\n        fixAndCompare(\"SmartCastExpected.kt\", \"SmartCastTest.kt\")\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/test/kotlin/com/saveourtool/diktat/ruleset/chapter4/SmartCastRuleWarnTest.kt",
    "content": "package com.saveourtool.diktat.ruleset.chapter4\n\nimport com.saveourtool.diktat.common.config.rules.DIKTAT_RULE_SET_ID\nimport com.saveourtool.diktat.ruleset.constants.Warnings\nimport com.saveourtool.diktat.ruleset.rules.chapter4.SmartCastRule\nimport com.saveourtool.diktat.util.LintTestBase\n\nimport com.saveourtool.diktat.api.DiktatError\nimport generated.WarningNames.SMART_CAST_NEEDED\nimport org.junit.jupiter.api.Disabled\nimport org.junit.jupiter.api.Tag\nimport org.junit.jupiter.api.Test\n\nclass SmartCastRuleWarnTest : LintTestBase(::SmartCastRule) {\n    private val ruleId = \"$DIKTAT_RULE_SET_ID:${SmartCastRule.NAME_ID}\"\n\n    @Test\n    @Tag(SMART_CAST_NEEDED)\n    fun `if with is smart cast good`() {\n        lintMethod(\n            \"\"\"\n                    |class Test {\n                    |   val x = \"\"\n                    |   fun someFun() {\n                    |       if (x is String) {\n                    |           val a = x.length\n                    |       }\n                    |   }\n                    |}\n            \"\"\".trimMargin()\n        )\n    }\n\n    @Test\n    @Tag(SMART_CAST_NEEDED)\n    fun `if with is smart cast bad`() {\n        lintMethod(\n            \"\"\"\n                    |class Test {\n                    |   val x = \"\"\n                    |   fun someFun() {\n                    |       if (x is String) {\n                    |           val a = (x as String).length\n                    |       }\n                    |   }\n                    |}\n            \"\"\".trimMargin(),\n            DiktatError(5, 21, ruleId, \"${Warnings.SMART_CAST_NEEDED.warnText()} x as String\", true)\n        )\n    }\n\n    @Test\n    @Tag(SMART_CAST_NEEDED)\n    fun `if with another if with is smart cast good`() {\n        lintMethod(\n            \"\"\"\n                    |class Test {\n                    |   val x = \"\"\n                    |   fun someFun() {\n                    |       if (x is String) {\n                    |           val a = x.length\n                    |           if (x is Int) {\n                    |               val a = x.value\n                    |           }\n                    |       }\n                    |   }\n                    |}\n            \"\"\".trimMargin()\n        )\n    }\n\n    @Test\n    @Tag(SMART_CAST_NEEDED)\n    fun `if with another if with is smart cast bad`() {\n        lintMethod(\n            \"\"\"\n                    |class Test {\n                    |   val x = \"\"\n                    |   fun someFun() {\n                    |       if (x is String) {\n                    |           val a = x.length\n                    |           if (x is Int) {\n                    |               val a = (x as Int).value\n                    |           }\n                    |       }\n                    |   }\n                    |}\n            \"\"\".trimMargin(),\n            DiktatError(7, 25, ruleId, \"${Warnings.SMART_CAST_NEEDED.warnText()} x as Int\", true)\n        )\n    }\n\n    @Test\n    @Tag(SMART_CAST_NEEDED)\n    fun `smart cast in else good`() {\n        lintMethod(\n            \"\"\"\n                    |class Test {\n                    |   val x = \"\"\n                    |   fun someFun() {\n                    |       if (x !is String) {\n                    |           val a = (x as String).length\n                    |       } else {\n                    |           val b = (x as String).length\n                    |       }\n                    |   }\n                    |}\n            \"\"\".trimMargin(),\n            DiktatError(7, 21, ruleId, \"${Warnings.SMART_CAST_NEEDED.warnText()} x as String\", true)\n        )\n    }\n\n    @Test\n    @Tag(SMART_CAST_NEEDED)\n    fun `smart cast in if without braces bad`() {\n        lintMethod(\n            \"\"\"\n                    |class Test {\n                    |   val x = \"\"\n                    |   fun someFun() {\n                    |       if (x is String)\n                    |           print((x as String).length)\n                    |   }\n                    |}\n            \"\"\".trimMargin(),\n            DiktatError(5, 19, ruleId, \"${Warnings.SMART_CAST_NEEDED.warnText()} x as String\", true)\n        )\n    }\n\n    @Test\n    @Tag(SMART_CAST_NEEDED)\n    fun `smart cast in if without braces good`() {\n        lintMethod(\n            \"\"\"\n                    |class Test {\n                    |   val x = \"\"\n                    |   fun someFun() {\n                    |       if (x is String)\n                    |           print(x.length)\n                    |   }\n                    |}\n            \"\"\".trimMargin()\n        )\n    }\n\n    @Test\n    @Tag(SMART_CAST_NEEDED)\n    fun `smart cast in else without braces good`() {\n        lintMethod(\n            \"\"\"\n                    |class Test {\n                    |   val x = \"\"\n                    |   fun someFun() {\n                    |       if (x !is String) {\n                    |           print(\"asd\")\n                    |       }\n                    |       else\n                    |           print((x as String).length)\n                    |   }\n                    |}\n            \"\"\".trimMargin(),\n            DiktatError(8, 19, ruleId, \"${Warnings.SMART_CAST_NEEDED.warnText()} x as String\", true)\n        )\n    }\n\n    @Test\n    @Tag(SMART_CAST_NEEDED)\n    fun `smart cast in else nested bad`() {\n        lintMethod(\n            \"\"\"\n                    |class Test {\n                    |   val x = \"\"\n                    |   fun someFun() {\n                    |       if (x !is String) {\n                    |           print(\"asd\")\n                    |       }\n                    |       else {\n                    |           print((x as String).length)\n                    |           val a = \"\"\n                    |           if (a !is String) {\n                    |\n                    |           } else {\n                    |               print((a as String).length)\n                    |           }\n                    |       }\n                    |   }\n                    |}\n            \"\"\".trimMargin(),\n            DiktatError(8, 19, ruleId, \"${Warnings.SMART_CAST_NEEDED.warnText()} x as String\", true),\n            DiktatError(13, 23, ruleId, \"${Warnings.SMART_CAST_NEEDED.warnText()} a as String\", true)\n        )\n    }\n\n    @Test\n    @Disabled(\"Rule is simplified after https://github.com/saveourtool/diktat/issues/1168\")\n    @Tag(SMART_CAST_NEEDED)\n    fun `smart cast in when bad`() {\n        lintMethod(\n            \"\"\"\n                    |class Test {\n                    |   val x = \"\"\n                    |   fun someFun() {\n                    |       when (x) {\n                    |           is Int -> print((x as Int).length)\n                    |           is String -> print(\"String\")\n                    |           is Long -> x as Int\n                    |       }\n                    |   }\n                    |}\n            \"\"\".trimMargin(),\n            DiktatError(5, 29, ruleId, \"${Warnings.SMART_CAST_NEEDED.warnText()} x as Int\", true)\n        )\n    }\n\n    @Test\n    @Tag(SMART_CAST_NEEDED)\n    fun `smart cast in when good`() {\n        lintMethod(\n            \"\"\"\n                    |class Test {\n                    |   val x = \"\"\n                    |   fun someFun() {\n                    |       when (x) {\n                    |           is Int -> print(x.length)\n                    |           is String -> print(\"String\")\n                    |       }\n                    |   }\n                    |}\n            \"\"\".trimMargin()\n        )\n    }\n\n    @Test\n    @Tag(SMART_CAST_NEEDED)\n    fun `smart cast in when good 2`() {\n        lintMethod(\n            \"\"\"\n                |fun SomeClass.foo() = when (mutableProperty) {\n                |    is Foo -> (mutableProperty as Foo).fooFoo()  // smart cast is required 'because 'mutableProperty' is a property that has open or custom getter'\n                |    else -> println(\"ok\")\n                |}\n            \"\"\".trimMargin()\n        )\n    }\n\n    @Test\n    @Tag(SMART_CAST_NEEDED)\n    fun `if with multiple is good`() {\n        lintMethod(\n            \"\"\"\n                    |class Test {\n                    |   val x = \"\"\n                    |   val y = 3\n                    |   fun someFun() {\n                    |       if (x is String || y is Int) {\n                    |           val a = x.length\n                    |           val b = y.value\n                    |       }\n                    |   }\n                    |}\n            \"\"\".trimMargin()\n        )\n    }\n\n    @Test\n    @Tag(SMART_CAST_NEEDED)\n    fun `if with multiple is bad`() {\n        lintMethod(\n            \"\"\"\n                    |class Test {\n                    |   val x = \"\"\n                    |   val y = 3\n                    |   fun someFun() {\n                    |       if (x is String || y is Int) {\n                    |           val a = (x as String).length\n                    |           val b = (y as Int).value\n                    |       }\n                    |   }\n                    |}\n            \"\"\".trimMargin(),\n            DiktatError(6, 21, ruleId, \"${Warnings.SMART_CAST_NEEDED.warnText()} x as String\", true),\n            DiktatError(7, 21, ruleId, \"${Warnings.SMART_CAST_NEEDED.warnText()} y as Int\", true)\n        )\n    }\n\n    @Test\n    @Tag(SMART_CAST_NEEDED)\n    fun `if with function condition`() {\n        lintMethod(\n            \"\"\"\n                    |class Test {\n                    |   val x = \"\"\n                    |   val list = listOf(1,2,3)\n                    |   fun someFun() {\n                    |       if (list.filter { it is Foo }.all { it.bar() }) {\n                    |           val a = x.length\n                    |           val b = y.value\n                    |       }\n                    |   }\n                    |}\n            \"\"\".trimMargin()\n        )\n    }\n\n    @Test\n    @Tag(SMART_CAST_NEEDED)\n    fun `if with shadowed var good`() {\n        lintMethod(\n            \"\"\"\n                    |class Test {\n                    |   val x = \"\"\n                    |   fun someFun() {\n                    |       if (x is String) {\n                    |           val x = 5\n                    |           val a = (x as String).length\n                    |       }\n                    |   }\n                    |}\n            \"\"\".trimMargin()\n        )\n    }\n\n    @Test\n    @Tag(SMART_CAST_NEEDED)\n    fun `if with shadowed var bad`() {\n        lintMethod(\n            \"\"\"\n                    |class Test {\n                    |   val x = \"\"\n                    |   fun someFun() {\n                    |       if (x is String) {\n                    |           val x = 5\n                    |           val a = (x as String).length\n                    |           if (x is Int) {\n                    |               val b = (x as Int).value\n                    |           }\n                    |       }\n                    |   }\n                    |}\n            \"\"\".trimMargin(),\n            DiktatError(8, 25, ruleId, \"${Warnings.SMART_CAST_NEEDED.warnText()} x as Int\", true)\n        )\n    }\n\n    @Test\n    @Tag(SMART_CAST_NEEDED)\n    fun `if with shadowed var bad 2`() {\n        lintMethod(\n            \"\"\"\n                    |class Test {\n                    |   val x = \"\"\n                    |   fun someFun() {\n                    |       if (x is String) {\n                    |           val x = 5\n                    |           val a = (x as Int).length\n                    |       }\n                    |   }\n                    |}\n            \"\"\".trimMargin(),\n            DiktatError(6, 21, ruleId, \"${Warnings.SMART_CAST_NEEDED.warnText()} x as Int\", true)\n        )\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/test/kotlin/com/saveourtool/diktat/ruleset/chapter4/TypeAliasRuleWarnTest.kt",
    "content": "package com.saveourtool.diktat.ruleset.chapter4\n\nimport com.saveourtool.diktat.common.config.rules.DIKTAT_RULE_SET_ID\nimport com.saveourtool.diktat.common.config.rules.RulesConfig\nimport com.saveourtool.diktat.ruleset.constants.Warnings.TYPE_ALIAS\nimport com.saveourtool.diktat.ruleset.rules.chapter4.TypeAliasRule\nimport com.saveourtool.diktat.util.LintTestBase\n\nimport com.saveourtool.diktat.api.DiktatError\nimport generated.WarningNames\nimport org.junit.jupiter.api.Tag\nimport org.junit.jupiter.api.Test\n\nclass TypeAliasRuleWarnTest : LintTestBase(::TypeAliasRule) {\n    private val ruleId = \"$DIKTAT_RULE_SET_ID:${TypeAliasRule.NAME_ID}\"\n    private val rulesConfigListShortType: List<RulesConfig> = listOf(\n        RulesConfig(TYPE_ALIAS.name, true,\n            mapOf(\"typeReferenceLength\" to \"4\"))\n    )\n\n    @Test\n    @Tag(WarningNames.TYPE_ALIAS)\n    fun `long reference with several MutableMaps`() {\n        lintMethod(\n            \"\"\"\n                    | val b: MutableMap<String, MutableList<String>>\n                    | val b = listof<Int>()\n            \"\"\".trimMargin(),\n            DiktatError(1, 9, ruleId, \"${TYPE_ALIAS.warnText()} too long type reference\", false)\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.TYPE_ALIAS)\n    fun `check long lambda property`() {\n        lintMethod(\n            \"\"\"\n                    | var emitWarn: (offset: Int, errorMessage: String, canBeAutoCorrected: Boolean) -> Unit\n                    | var emitWarn: (offset: Int, (T) -> Boolean) -> Unit\n            \"\"\".trimMargin(),\n            DiktatError(1, 16, ruleId, \"${TYPE_ALIAS.warnText()} too long type reference\", false),\n            DiktatError(2, 16, ruleId, \"${TYPE_ALIAS.warnText()} too long type reference\", false)\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.TYPE_ALIAS)\n    fun `correct type length`() {\n        lintMethod(\n            \"\"\"\n                    | var emitWarn: Int\n                    | val b = mutableMapOf<String, MutableList<String>>()\n                    |\n                    | fun foo(): MutableMap<String, MutableList<String>> {\n                    | }\n                    |\n            \"\"\".trimMargin(),\n            DiktatError(4, 13, ruleId, \"${TYPE_ALIAS.warnText()} too long type reference\", false)\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.TYPE_ALIAS)\n    fun `correct type length but with configuration`() {\n        lintMethod(\n            \"\"\"\n                    | var emitWarn: Int\n                    | val flag: (T) -> Boolean\n                    | val list: List<List<Int>>\n                    |\n            \"\"\".trimMargin(),\n            DiktatError(3, 12, ruleId, \"${TYPE_ALIAS.warnText()} too long type reference\", false),\n            rulesConfigList = rulesConfigListShortType\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.TYPE_ALIAS)\n    fun `should ignore inheritance`() {\n        lintMethod(\n            \"\"\"\n                    | class A : JsonResourceConfigReader<List<RulesConfig>>() {\n                    |   fun foo() : JsonResourceConfigReader<List<RulesConfig>> {}\n                    |   val q: JsonResourceConfigReader<List<RulesConfig>>? = null\n                    |   fun goo() {\n                    |       class B : JsonResourceConfigReader<List<RulesConfig>> {}\n                    |   }\n                    | }\n            \"\"\".trimMargin(),\n            DiktatError(2, 16, ruleId, \"${TYPE_ALIAS.warnText()} too long type reference\", false),\n            DiktatError(3, 11, ruleId, \"${TYPE_ALIAS.warnText()} too long type reference\", false)\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.TYPE_ALIAS)\n    fun `check correct examle`() {\n        lintMethod(\n            \"\"\"\n                    |typealias jsonType = JsonResourceConfigReader<List<RulesConfig>>\n                    |class A : JsonResourceConfigReader<List<RulesConfig>>() {\n                    |\n                    |   fun foo() : jsonType {}\n                    |   val q: jsonType? = null\n                    |   fun goo() {\n                    |       class B : JsonResourceConfigReader<List<RulesConfig>> {}\n                    |   }\n                    |}\n            \"\"\".trimMargin()\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.TYPE_ALIAS)\n    fun `check lazy property`() {\n        lintMethod(\n            \"\"\"\n                    |class A {\n                    |   val q: List<Map<Int, Int>> by lazy  {\n                    |       emptyList<Map<Int, Int>>()\n                    |   }\n                    |}\n            \"\"\".trimMargin(),\n            DiktatError(2, 11, ruleId, \"${TYPE_ALIAS.warnText()} too long type reference\", false),\n            rulesConfigList = rulesConfigListShortType\n        )\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/test/kotlin/com/saveourtool/diktat/ruleset/chapter4/VariableGenericTypeDeclarationRuleFixTest.kt",
    "content": "package com.saveourtool.diktat.ruleset.chapter4\n\nimport com.saveourtool.diktat.ruleset.rules.chapter4.VariableGenericTypeDeclarationRule\nimport com.saveourtool.diktat.util.FixTestBase\n\nimport generated.WarningNames\nimport org.junit.jupiter.api.Tag\nimport org.junit.jupiter.api.Test\n\nclass VariableGenericTypeDeclarationRuleFixTest : FixTestBase(\"test/paragraph4/generics\", ::VariableGenericTypeDeclarationRule) {\n    @Test\n    @Tag(WarningNames.GENERIC_VARIABLE_WRONG_DECLARATION)\n    fun `basic fix test`() {\n        fixAndCompare(\"VariableGenericTypeDeclarationExpected.kt\", \"VariableGenericTypeDeclarationTest.kt\")\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/test/kotlin/com/saveourtool/diktat/ruleset/chapter4/VariableGenericTypeDeclarationRuleWarnTest.kt",
    "content": "package com.saveourtool.diktat.ruleset.chapter4\n\nimport com.saveourtool.diktat.common.config.rules.DIKTAT_RULE_SET_ID\nimport com.saveourtool.diktat.ruleset.constants.Warnings\nimport com.saveourtool.diktat.ruleset.rules.chapter4.VariableGenericTypeDeclarationRule\nimport com.saveourtool.diktat.util.LintTestBase\n\nimport com.saveourtool.diktat.api.DiktatError\nimport generated.WarningNames.GENERIC_VARIABLE_WRONG_DECLARATION\nimport org.junit.jupiter.api.Tag\nimport org.junit.jupiter.api.Test\n\nclass VariableGenericTypeDeclarationRuleWarnTest : LintTestBase(::VariableGenericTypeDeclarationRule) {\n    private val ruleId = \"$DIKTAT_RULE_SET_ID:${VariableGenericTypeDeclarationRule.NAME_ID}\"\n\n    @Test\n    @Tag(GENERIC_VARIABLE_WRONG_DECLARATION)\n    fun `property with generic type good`() {\n        lintMethod(\n            \"\"\"\n                    |class SomeClass {\n                    |   val myVariable: Map<Int, String> = emptyMap()\n                    |   val lazyValue: Map<Int, String> by lazy {\n                    |       println(\"computed!\")\n                    |       emptyMap<Int, String>()\n                    |   }\n                    |   val sideRegex = Regex(\"<([a-zA-Z, <>?]+)>\")\n                    |   val str = someMethod(\"mapOf<String>\")\n                    |   val x = foo.bar<Bar>().baz()\n                    |}\n            \"\"\".trimMargin()\n        )\n    }\n\n    @Test\n    @Tag(GENERIC_VARIABLE_WRONG_DECLARATION)\n    fun `property with generic type bad`() {\n        lintMethod(\n            \"\"\"\n                    |class SomeClass {\n                    |   val myVariable: Map<Int, String> = emptyMap<Int, String>()\n                    |   val any = Array<Any>(3) { \"\" }\n                    |   val x = foo.bar<Bar>().baz<Some>()\n                    |}\n            \"\"\".trimMargin(),\n            DiktatError(2, 4, ruleId,\n                \"${Warnings.GENERIC_VARIABLE_WRONG_DECLARATION.warnText()} type arguments are unnecessary in emptyMap<Int, String>()\", true),\n            DiktatError(3, 4, ruleId,\n                \"${Warnings.GENERIC_VARIABLE_WRONG_DECLARATION.warnText()} val any = Array<Any>(3) { \\\"\\\" }\", false),\n            DiktatError(4, 4, ruleId,\n                \"${Warnings.GENERIC_VARIABLE_WRONG_DECLARATION.warnText()} val x = foo.bar<Bar>().baz<Some>()\", false)\n        )\n    }\n\n    @Test\n    @Tag(GENERIC_VARIABLE_WRONG_DECLARATION)\n    fun `property in function as parameter good`() {\n        lintMethod(\n            \"\"\"\n                    |class SomeClass {\n                    |   private fun someFunc(myVariable: Map<Int, String> = emptyMap()) {\n                    |\n                    |   }\n                    |}\n            \"\"\".trimMargin()\n        )\n    }\n\n    @Test\n    @Tag(GENERIC_VARIABLE_WRONG_DECLARATION)\n    fun `property in function as parameter with wildcard type good`() {\n        lintMethod(\n            \"\"\"\n                    |class SomeClass {\n                    |   private fun someFunc(myVariable: List<*> = emptyList<Int>()) {\n                    |\n                    |   }\n                    |}\n            \"\"\".trimMargin()\n        )\n    }\n\n    @Test\n    @Tag(GENERIC_VARIABLE_WRONG_DECLARATION)\n    fun `property in function as parameter with wildcard type good 2`() {\n        lintMethod(\n            \"\"\"\n                    |class SomeClass {\n                    |   private fun someFunc(myVariable: Map<*, String> = emptyMap<Int, String>()) {\n                    |\n                    |   }\n                    |}\n            \"\"\".trimMargin()\n        )\n    }\n\n    @Test\n    @Tag(GENERIC_VARIABLE_WRONG_DECLARATION)\n    fun `property in function as parameter bad`() {\n        lintMethod(\n            \"\"\"\n                    |class SomeClass {\n                    |   private fun someFunc(myVariable: Map<Int, String> = emptyMap<Int, String>()) {\n                    |\n                    |   }\n                    |}\n            \"\"\".trimMargin(),\n            DiktatError(2, 25, ruleId,\n                \"${Warnings.GENERIC_VARIABLE_WRONG_DECLARATION.warnText()} type arguments are unnecessary in emptyMap<Int, String>()\", true)\n        )\n    }\n\n    @Test\n    @Tag(GENERIC_VARIABLE_WRONG_DECLARATION)\n    fun `property in function good`() {\n        lintMethod(\n            \"\"\"\n                    |class SomeClass {\n                    |   private fun someFunc() {\n                    |       val myVariable: Map<Int, String> = emptyMap()\n                    |   }\n                    |}\n            \"\"\".trimMargin()\n        )\n    }\n\n    @Test\n    @Tag(GENERIC_VARIABLE_WRONG_DECLARATION)\n    fun `property in function with wildcard type good`() {\n        lintMethod(\n            \"\"\"\n                    |class SomeClass {\n                    |   private fun someFunc() {\n                    |       val myVariable: List<*> = emptyList<Int>()\n                    |   }\n                    |}\n            \"\"\".trimMargin()\n        )\n    }\n\n    @Test\n    @Tag(GENERIC_VARIABLE_WRONG_DECLARATION)\n    fun `property in function bad`() {\n        lintMethod(\n            \"\"\"\n                    |class SomeClass {\n                    |   private fun someFunc() {\n                    |       val myVariable: Map<Int, String> = emptyMap<Int, String>()\n                    |   }\n                    |}\n            \"\"\".trimMargin(),\n            DiktatError(3, 8, ruleId,\n                \"${Warnings.GENERIC_VARIABLE_WRONG_DECLARATION.warnText()} type arguments are unnecessary in emptyMap<Int, String>()\", true)\n        )\n    }\n\n    @Test\n    @Tag(GENERIC_VARIABLE_WRONG_DECLARATION)\n    fun `property in class good`() {\n        lintMethod(\n            \"\"\"\n                    |class SomeClass(val myVariable: Map<Int, String> = emptyMap()) {\n                    |\n                    |}\n            \"\"\".trimMargin()\n        )\n    }\n\n    @Test\n    @Tag(GENERIC_VARIABLE_WRONG_DECLARATION)\n    fun `property in class with wildcard type good`() {\n        lintMethod(\n            \"\"\"\n                    |class SomeClass(val myVariable: List<*> = emptyList<Int>()) {\n                    |\n                    |}\n            \"\"\".trimMargin()\n        )\n    }\n\n    @Test\n    @Tag(GENERIC_VARIABLE_WRONG_DECLARATION)\n    fun `property in class bad`() {\n        lintMethod(\n            \"\"\"\n                    |class SomeClass(val myVariable: Map<Int, String> = emptyMap<Int, String>()) {\n                    |\n                    |}\n            \"\"\".trimMargin(),\n            DiktatError(1, 17, ruleId,\n                \"${Warnings.GENERIC_VARIABLE_WRONG_DECLARATION.warnText()} type arguments are unnecessary in emptyMap<Int, String>()\", true)\n        )\n    }\n\n    @Test\n    @Tag(GENERIC_VARIABLE_WRONG_DECLARATION)\n    fun `property with multiple generics`() {\n        lintMethod(\n            \"\"\"\n                    |class SomeClass {\n                    |   private fun someFunc() {\n                    |       val myVariable: Map<Int, Map<String>> = emptyMap<Int, Map<String>>()\n                    |   }\n                    |}\n            \"\"\".trimMargin(),\n            DiktatError(3, 8, ruleId,\n                \"${Warnings.GENERIC_VARIABLE_WRONG_DECLARATION.warnText()} type arguments are unnecessary in emptyMap<Int, Map<String>>()\", true)\n        )\n    }\n\n    @Test\n    @Tag(GENERIC_VARIABLE_WRONG_DECLARATION)\n    fun `should not trigger`() {\n        lintMethod(\n            \"\"\"\n                    |class SomeClass {\n                    |   private fun someFunc() {\n                    |       var myVariable: Map<Int, Any> = emptyMap<Int, String>()\n                    |   }\n                    |}\n            \"\"\".trimMargin()\n        )\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/test/kotlin/com/saveourtool/diktat/ruleset/chapter5/AsyncAndSyncRuleTest.kt",
    "content": "package com.saveourtool.diktat.ruleset.chapter5\n\nimport com.saveourtool.diktat.common.config.rules.DIKTAT_RULE_SET_ID\nimport com.saveourtool.diktat.ruleset.constants.Warnings.RUN_BLOCKING_INSIDE_ASYNC\nimport com.saveourtool.diktat.ruleset.rules.chapter5.AsyncAndSyncRule\nimport com.saveourtool.diktat.util.LintTestBase\n\nimport com.saveourtool.diktat.api.DiktatError\nimport generated.WarningNames\nimport org.junit.jupiter.api.Tag\nimport org.junit.jupiter.api.Test\n\nclass AsyncAndSyncRuleTest : LintTestBase(::AsyncAndSyncRule) {\n    private val ruleId = \"$DIKTAT_RULE_SET_ID:${AsyncAndSyncRule.NAME_ID}\"\n\n    @Test\n    @Tag(WarningNames.RUN_BLOCKING_INSIDE_ASYNC)\n    fun `test wrong case`() {\n        lintMethod(\n            \"\"\"\n                    |fun foo() {\n                    |   GlobalScope.launch {\n                    |       c.addAndGet(i)\n                    |   }\n                    |\n                    |   GlobalScope.async {\n                    |       n\n                    |   }\n                    |\n                    |   GlobalScope.async {\n                    |       runBlocking {\n                    |\n                    |       }\n                    |   }\n                    |}\n                    |\n                    |suspend fun foo() {\n                    |   runBlocking {\n                    |       delay(2000)\n                    |   }\n                    |}\n                    |\n            \"\"\".trimMargin(),\n            DiktatError(11, 8, ruleId, \"${RUN_BLOCKING_INSIDE_ASYNC.warnText()} runBlocking\", false),\n            DiktatError(18, 4, ruleId, \"${RUN_BLOCKING_INSIDE_ASYNC.warnText()} runBlocking\", false)\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.RUN_BLOCKING_INSIDE_ASYNC)\n    fun `test dot qualified expression case`() {\n        lintMethod(\n            \"\"\"\n                    |fun foo() {\n                    |   GlobalScope.async {\n                    |       node.runBlocking()\n                    |       runBlocking {\n                    |           n++\n                    |       }\n                    |   }\n                    |}\n                    |\n                    |fun goo() {\n                    |   runBlocking {\n                    |       GlobalScope.async {\n                    |           n++\n                    |       }\n                    |   }\n                    |}\n            \"\"\".trimMargin(),\n            DiktatError(4, 8, ruleId, \"${RUN_BLOCKING_INSIDE_ASYNC.warnText()} runBlocking\", false)\n        )\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/test/kotlin/com/saveourtool/diktat/ruleset/chapter5/AvoidNestedFunctionsFixTest.kt",
    "content": "package com.saveourtool.diktat.ruleset.chapter5\n\nimport com.saveourtool.diktat.ruleset.rules.chapter5.AvoidNestedFunctionsRule\nimport com.saveourtool.diktat.util.FixTestBase\n\nimport generated.WarningNames\nimport org.junit.jupiter.api.Tag\nimport org.junit.jupiter.api.Test\n\nclass AvoidNestedFunctionsFixTest : FixTestBase(\"test/paragraph5/nested_functions\", ::AvoidNestedFunctionsRule) {\n    @Test\n    @Tag(WarningNames.AVOID_NESTED_FUNCTIONS)\n    fun `fix nested functions`() {\n        fixAndCompare(\"AvoidNestedFunctionsExample.kt\", \"AvoidNestedFunctionsTest.kt\")\n    }\n    @Test\n    @Tag(WarningNames.AVOID_NESTED_FUNCTIONS)\n    fun `fix several nested functions`() {\n        fixAndCompare(\"AvoidNestedFunctionsSeveralExample.kt\", \"AvoidNestedFunctionsSeveralTest.kt\")\n    }\n\n    @Test\n    @Tag(WarningNames.AVOID_NESTED_FUNCTIONS)\n    fun `should not change`() {\n        fixAndCompare(\"AvoidNestedFunctionsNoTriggerExample.kt\", \"AvoidNestedFunctionsNoTriggerTest.kt\")\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/test/kotlin/com/saveourtool/diktat/ruleset/chapter5/AvoidNestedFunctionsWarnTest.kt",
    "content": "package com.saveourtool.diktat.ruleset.chapter5\n\nimport com.saveourtool.diktat.common.config.rules.DIKTAT_RULE_SET_ID\nimport com.saveourtool.diktat.ruleset.constants.Warnings\nimport com.saveourtool.diktat.ruleset.rules.chapter5.AvoidNestedFunctionsRule\nimport com.saveourtool.diktat.util.LintTestBase\n\nimport com.saveourtool.diktat.api.DiktatError\nimport generated.WarningNames.AVOID_NESTED_FUNCTIONS\nimport org.junit.jupiter.api.Tag\nimport org.junit.jupiter.api.Test\n\nclass AvoidNestedFunctionsWarnTest : LintTestBase(::AvoidNestedFunctionsRule) {\n    private val ruleId = \"$DIKTAT_RULE_SET_ID:${AvoidNestedFunctionsRule.NAME_ID}\"\n\n    @Test\n    @Tag(AVOID_NESTED_FUNCTIONS)\n    fun `nested function`() {\n        lintMethod(\n            \"\"\"\n                    |fun foo() {\n                    |   someFunc()\n                    |   fun bar(a:String, b:Int) {\n                    |       val param = 5\n                    |       val repeatFun: String.(Int) -> String = { times -> this.repeat(times) }\n                    |       param.value\n                    |       repeatFun(45)\n                    |       some(a)\n                    |       some(b)\n                    |   }\n                    |\n                    |}\n            \"\"\".trimMargin(),\n            DiktatError(3, 4, ruleId, \"${Warnings.AVOID_NESTED_FUNCTIONS.warnText()} fun bar\", false)\n        )\n    }\n\n    @Test\n    @Tag(AVOID_NESTED_FUNCTIONS)\n    fun `anonymous function`() {\n        val code = \"\"\"\n            package com.saveourtool.diktat.test\n\n            fun foo() {\n                val sum: (Int) -> Int = fun(x): Int = x + x\n            }\n\n        \"\"\".trimIndent()\n        lintMethod(code)\n    }\n\n    @Test\n    @Tag(AVOID_NESTED_FUNCTIONS)\n    fun `several nested functions`() {\n        lintMethod(\n            \"\"\"\n                    |fun foo() {\n                    |\n                    |   fun bar() {\n                    |       fun baz() {\n                    |       }\n                    |   }\n                    |\n                    |}\n            \"\"\".trimMargin(),\n            DiktatError(3, 4, ruleId, \"${Warnings.AVOID_NESTED_FUNCTIONS.warnText()} fun bar\", true),\n            DiktatError(4, 8, ruleId, \"${Warnings.AVOID_NESTED_FUNCTIONS.warnText()} fun baz\", true)\n        )\n    }\n\n    @Test\n    @Tag(AVOID_NESTED_FUNCTIONS)\n    fun `no nested functions`() {\n        lintMethod(\n            \"\"\"\n                    |class SomeClass {\n                    |   fun someFunc() {}\n                    |\n                    |   fun anotherFunc() {}\n                    |\n                    |   fun moreFunction() {}\n                    |}\n            \"\"\".trimMargin()\n        )\n    }\n\n    @Test\n    @Tag(AVOID_NESTED_FUNCTIONS)\n    fun `nested functions in anonymous class`() {\n        lintMethod(\n            \"\"\"\n                    |class SomeClass {\n                    |fun some() {\n                    |       listOf(\n                    |              RuleSet(\"test\", object : Rule(\"astnode-utils-test\") {\n                    |                   override fun visit(node: ASTNode,\n                    |                   autoCorrect: Boolean,\n                    |                   emit: (offset: Int, errorMessage: String, canBeAutoCorrected: Boolean) -> Unit) {\n                    |                   applyToNode(node, counter)\n                    |                   }\n                    |           }))\n                    |   }\n                    |}\n            \"\"\".trimMargin()\n        )\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/test/kotlin/com/saveourtool/diktat/ruleset/chapter5/CheckInverseMethodRuleFixTest.kt",
    "content": "package com.saveourtool.diktat.ruleset.chapter5\n\nimport com.saveourtool.diktat.ruleset.rules.chapter5.CheckInverseMethodRule\nimport com.saveourtool.diktat.util.FixTestBase\n\nimport generated.WarningNames.INVERSE_FUNCTION_PREFERRED\nimport org.junit.jupiter.api.Tag\nimport org.junit.jupiter.api.Test\n\nclass CheckInverseMethodRuleFixTest : FixTestBase(\"test/paragraph5/method_call_names\", ::CheckInverseMethodRule) {\n    @Test\n    @Tag(INVERSE_FUNCTION_PREFERRED)\n    fun `should fix method calls`() {\n        fixAndCompare(\"ReplaceMethodCallNamesExpected.kt\", \"ReplaceMethodCallNamesTest.kt\")\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/test/kotlin/com/saveourtool/diktat/ruleset/chapter5/CheckInverseMethodRuleWarnTest.kt",
    "content": "package com.saveourtool.diktat.ruleset.chapter5\n\nimport com.saveourtool.diktat.common.config.rules.DIKTAT_RULE_SET_ID\nimport com.saveourtool.diktat.ruleset.constants.Warnings\nimport com.saveourtool.diktat.ruleset.rules.chapter5.CheckInverseMethodRule\nimport com.saveourtool.diktat.util.LintTestBase\n\nimport com.saveourtool.diktat.api.DiktatError\nimport generated.WarningNames.INVERSE_FUNCTION_PREFERRED\nimport org.junit.jupiter.api.Tag\nimport org.junit.jupiter.api.Test\n\nclass CheckInverseMethodRuleWarnTest : LintTestBase(::CheckInverseMethodRule) {\n    private val ruleId = \"$DIKTAT_RULE_SET_ID:${CheckInverseMethodRule.NAME_ID}\"\n\n    @Test\n    @Tag(INVERSE_FUNCTION_PREFERRED)\n    fun `should not raise warning`() {\n        lintMethod(\n            \"\"\"\n                    |fun some() {\n                    |   if (list.isEmpty()) {\n                    |       // some cool logic\n                    |   }\n                    |}\n            \"\"\".trimMargin()\n        )\n    }\n\n    @Test\n    @Tag(INVERSE_FUNCTION_PREFERRED)\n    fun `should raise warning`() {\n        lintMethod(\n            \"\"\"\n                    |fun some() {\n                    |   if (!list.isEmpty()) {\n                    |       // some cool logic\n                    |   }\n                    |}\n            \"\"\".trimMargin(),\n            DiktatError(2, 14, ruleId, \"${Warnings.INVERSE_FUNCTION_PREFERRED.warnText()} isNotEmpty() instead of !isEmpty()\", true)\n        )\n    }\n\n    @Test\n    @Tag(INVERSE_FUNCTION_PREFERRED)\n    fun `should consider white spaces between ! and call expression`() {\n        lintMethod(\n            \"\"\"\n                    |fun some() {\n                    |   if (!  list.isEmpty()) {\n                    |       // some cool logic\n                    |   }\n                    |}\n            \"\"\".trimMargin(),\n            DiktatError(2, 16, ruleId, \"${Warnings.INVERSE_FUNCTION_PREFERRED.warnText()} isNotEmpty() instead of !isEmpty()\", true)\n        )\n    }\n\n    @Test\n    @Tag(INVERSE_FUNCTION_PREFERRED)\n    fun `should consider comments between ! and call expression`() {\n        lintMethod(\n            \"\"\"\n                    |fun some() {\n                    |   if (! /*cool comment*/ list.isEmpty()) {\n                    |       // some cool logic\n                    |   }\n                    |}\n            \"\"\".trimMargin(),\n            DiktatError(2, 32, ruleId, \"${Warnings.INVERSE_FUNCTION_PREFERRED.warnText()} isNotEmpty() instead of !isEmpty()\", true)\n        )\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/test/kotlin/com/saveourtool/diktat/ruleset/chapter5/CustomLabelsTest.kt",
    "content": "package com.saveourtool.diktat.ruleset.chapter5\n\nimport com.saveourtool.diktat.common.config.rules.DIKTAT_RULE_SET_ID\nimport com.saveourtool.diktat.ruleset.constants.Warnings.CUSTOM_LABEL\nimport com.saveourtool.diktat.ruleset.rules.chapter5.CustomLabel\nimport com.saveourtool.diktat.util.LintTestBase\n\nimport com.saveourtool.diktat.api.DiktatError\nimport generated.WarningNames\nimport org.junit.jupiter.api.Tag\nimport org.junit.jupiter.api.Test\n\nclass CustomLabelsTest : LintTestBase(::CustomLabel) {\n    private val ruleId = \"$DIKTAT_RULE_SET_ID:${CustomLabel.NAME_ID}\"\n\n    @Test\n    @Tag(WarningNames.CUSTOM_LABEL)\n    fun `should trigger custom label`() {\n        lintMethod(\n            \"\"\"\n                    fun foo() {\n                        run qwe@ {\n                            q.forEach {\n                                return@qwe\n                            }\n                        }\n                        q.forEachIndexed { index, i ->\n                            return@forEachIndexed\n                        }\n                        loop@ for(i: Int in q) {\n                            println(i)\n                            break@loop\n                        }\n                        qq@ for(i: Int in q) {\n                            println(i)\n                            break@qq\n                        }\n                        q.run {\n                            it.map {\n                                it.foreach{\n                                    break@forEach\n                                }\n                            }\n                        }\n                    }\n            \"\"\".trimMargin(),\n            DiktatError(4, 39, ruleId, \"${CUSTOM_LABEL.warnText()} @qwe\", false),\n            DiktatError(16, 34, ruleId, \"${CUSTOM_LABEL.warnText()} @qq\", false)\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.CUSTOM_LABEL)\n    fun `should not trigger custom label in nested expression`() {\n        lintMethod(\n            \"\"\"\n                fun foo() {\n                    qq@ for(i: Int in q) {\n                        for (j: Int in q) {\n                            println(i)\n                            break@qq\n                        }\n                    }\n\n                    q.forEach outer@ {\n                        it.forEach {\n                            if(it == 21)\n                                return@outer\n                        }\n                    }\n                }\n            \"\"\".trimMargin()\n        )\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/test/kotlin/com/saveourtool/diktat/ruleset/chapter5/FunctionArgumentsSizeWarnTest.kt",
    "content": "package com.saveourtool.diktat.ruleset.chapter5\n\nimport com.saveourtool.diktat.common.config.rules.DIKTAT_RULE_SET_ID\nimport com.saveourtool.diktat.common.config.rules.RulesConfig\nimport com.saveourtool.diktat.ruleset.constants.Warnings.TOO_MANY_PARAMETERS\nimport com.saveourtool.diktat.ruleset.rules.chapter5.FunctionArgumentsSize\nimport com.saveourtool.diktat.util.LintTestBase\n\nimport com.saveourtool.diktat.api.DiktatError\nimport generated.WarningNames\nimport org.junit.jupiter.api.Tag\nimport org.junit.jupiter.api.Test\n\nclass FunctionArgumentsSizeWarnTest : LintTestBase(::FunctionArgumentsSize) {\n    private val ruleId = \"$DIKTAT_RULE_SET_ID:${FunctionArgumentsSize.NAME_ID}\"\n    private val rulesConfigList: List<RulesConfig> = listOf(\n        RulesConfig(TOO_MANY_PARAMETERS.name, true,\n            mapOf(\"maxParameterListSize\" to \"1\"))\n    )\n\n    @Test\n    @Tag(WarningNames.TOO_MANY_PARAMETERS)\n    fun `check simple function`() {\n        lintMethod(\n            \"\"\"\n                    |fun foo(a: Int, b: Int, c: Int, d: Int, e: Int, f: Int) {}\n                    |fun foo(a: Int, b: Int, c: Int, d: Int, e: Int, myLambda: () -> Unit) {}\n                    |fun foo(a: Int, b: Int, c: Int, d: Int, myLambda: () -> Unit) {}\n                    |fun foo(a: Int, b: Int, c: Int, d: Int, e: Int, myLambda: () -> Unit) = 10\n                    |abstract fun foo(a: Int, b: Int, c: Int, d: Int, e: Int, f: Int)\n            \"\"\".trimMargin(),\n            DiktatError(1, 1, ruleId, \"${TOO_MANY_PARAMETERS.warnText()} foo has 6, but allowed 5\", false),\n            DiktatError(2, 1, ruleId, \"${TOO_MANY_PARAMETERS.warnText()} foo has 6, but allowed 5\", false),\n            DiktatError(4, 1, ruleId, \"${TOO_MANY_PARAMETERS.warnText()} foo has 6, but allowed 5\", false),\n            DiktatError(5, 1, ruleId, \"${TOO_MANY_PARAMETERS.warnText()} foo has 6, but allowed 5\", false)\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.TOO_MANY_PARAMETERS)\n    fun `check function with config`() {\n        lintMethod(\n            \"\"\"\n                    |fun foo(a: Int, b: Int) {}\n            \"\"\".trimMargin(),\n            DiktatError(1, 1, ruleId, \"${TOO_MANY_PARAMETERS.warnText()} foo has 2, but allowed 1\", false),\n            rulesConfigList = rulesConfigList\n        )\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/test/kotlin/com/saveourtool/diktat/ruleset/chapter5/FunctionLengthWarnTest.kt",
    "content": "package com.saveourtool.diktat.ruleset.chapter5\n\nimport com.saveourtool.diktat.common.config.rules.DIKTAT_RULE_SET_ID\nimport com.saveourtool.diktat.common.config.rules.RulesConfig\nimport com.saveourtool.diktat.ruleset.constants.Warnings.TOO_LONG_FUNCTION\nimport com.saveourtool.diktat.ruleset.rules.chapter5.FunctionLength\nimport com.saveourtool.diktat.util.LintTestBase\n\nimport com.saveourtool.diktat.api.DiktatError\nimport generated.WarningNames\nimport org.junit.jupiter.api.Tag\nimport org.junit.jupiter.api.Test\n\nclass FunctionLengthWarnTest : LintTestBase(::FunctionLength) {\n    private val ruleId = \"$DIKTAT_RULE_SET_ID:${FunctionLength.NAME_ID}\"\n    private val rulesConfigList: List<RulesConfig> = listOf(\n        RulesConfig(TOO_LONG_FUNCTION.name, true,\n            mapOf(\"maxFunctionLength\" to \"5\"))\n    )\n    private val shortRulesConfigList: List<RulesConfig> = listOf(\n        RulesConfig(TOO_LONG_FUNCTION.name, true,\n            mapOf(\"maxFunctionLength\" to \"2\"))\n    )\n    private val shortRulesWithoutHeaderConfigList: List<RulesConfig> = listOf(\n        RulesConfig(TOO_LONG_FUNCTION.name, true,\n            mapOf(\"maxFunctionLength\" to \"3\", \"isIncludeHeader\" to \"false\"))\n    )\n\n    @Test\n    @Tag(WarningNames.TOO_LONG_FUNCTION)\n    fun `check with all comment`() {\n        lintMethod(\n            \"\"\"\n                    |fun foo() {\n                    |\n                    |   //dkfgvdf\n                    |\n                    |   /*\n                    |    * jkgh\n                    |    */\n                    |\n                    |    /**\n                    |     * dfkjvbhdfkjb\n                    |     */\n                    |\n                    |   val x = 10\n                    |   val y = 100\n                    |   println(x)\n                    |   val z = x + y\n                    |   println(x)\n                    |\n                    |}\n            \"\"\".trimMargin(),\n            DiktatError(1, 1, ruleId, \"${TOO_LONG_FUNCTION.warnText()} max length is 5, but you have 7\", false),\n            rulesConfigList = rulesConfigList\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.TOO_LONG_FUNCTION)\n    fun `less than max`() {\n        lintMethod(\n            \"\"\"\n                    |fun foo() {\n                    |\n                    |\n                    |\n                    |\n                    |\n                    |\n                    |   val x = 10\n                    |   val y = 100\n                    |   println(x)\n                    |\n                    |}\n            \"\"\".trimMargin(),\n            rulesConfigList = rulesConfigList\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.TOO_LONG_FUNCTION)\n    fun `one line function`() {\n        lintMethod(\n            \"\"\"\n                    |fun foo(list: List<ASTNode>) = list.forEach {\n                    |        if (it.element == \"dfscv\")\n                    |           println()\n                    |}\n                    |\n                    |fun goo() =\n                    |   10\n            \"\"\".trimMargin(),\n            DiktatError(1, 1, ruleId, \"${TOO_LONG_FUNCTION.warnText()} max length is 2, but you have 4\", false),\n            rulesConfigList = shortRulesConfigList\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.TOO_LONG_FUNCTION)\n    fun `fun in class`() {\n        lintMethod(\n            \"\"\"\n                    |class A() {\n                    |   val x = 10\n                    |   val y  = 11\n                    |\n                    |   fun foo() {\n                    |       if(true) {\n                    |           while(true) {\n                    |               println(x)\n                    |               println(y)\n                    |           }\n                    |       }\n                    |   }\n                    |\n                    |}\n            \"\"\".trimMargin(),\n            DiktatError(5, 4, ruleId, \"${TOO_LONG_FUNCTION.warnText()} max length is 2, but you have 8\", false),\n            rulesConfigList = shortRulesConfigList\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.TOO_LONG_FUNCTION)\n    fun `check suppress`() {\n        lintMethod(\n            \"\"\"\n                    |@Suppress(\"TOO_LONG_FUNCTION\")\n                    |class A() {\n                    |   val x = 10\n                    |   val y  = 11\n                    |\n                    |\n                    |   fun foo() {\n                    |       if(true) {\n                    |           while(true) {\n                    |               println(x)\n                    |               println(y)\n                    |           }\n                    |       }\n                    |   }\n                    |\n                    |}\n            \"\"\".trimMargin(),\n            rulesConfigList = shortRulesConfigList\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.TOO_LONG_FUNCTION)\n    fun `only empty lines`() {\n        lintMethod(\n            \"\"\"\n                    |fun foo(list: List<ASTNode>) {\n                    |\n                    |\n                    |\n                    |\n                    |}\n            \"\"\".trimMargin(),\n            rulesConfigList = shortRulesConfigList\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.TOO_LONG_FUNCTION)\n    fun `fun longer but without body`() {\n        lintMethod(\n            \"\"\"\n                    |class A() {\n                    |   val x = 10\n                    |   val y  = 11\n                    |\n                    |   fun foo()\n                    |   {\n                    |       println(123)\n                    |   }\n                    |\n                    |}\n                    |\n                    |abstract class B {\n                    |   abstract fun foo()\n                    |}\n            \"\"\".trimMargin(),\n            rulesConfigList = shortRulesWithoutHeaderConfigList\n        )\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/test/kotlin/com/saveourtool/diktat/ruleset/chapter5/LambdaLengthWarnTest.kt",
    "content": "package com.saveourtool.diktat.ruleset.chapter5\n\nimport com.saveourtool.diktat.common.config.rules.DIKTAT_RULE_SET_ID\nimport com.saveourtool.diktat.common.config.rules.RulesConfig\nimport com.saveourtool.diktat.ruleset.constants.Warnings\nimport com.saveourtool.diktat.ruleset.rules.chapter5.LambdaLengthRule\nimport com.saveourtool.diktat.util.LintTestBase\n\nimport com.saveourtool.diktat.api.DiktatError\nimport generated.WarningNames\nimport org.junit.jupiter.api.Tag\nimport org.junit.jupiter.api.Test\n\nclass LambdaLengthWarnTest : LintTestBase(::LambdaLengthRule) {\n    private val ruleId = \"$DIKTAT_RULE_SET_ID:${LambdaLengthRule.NAME_ID}\"\n    private val rulesConfigList: List<RulesConfig> = listOf(\n        RulesConfig(\n            Warnings.TOO_MANY_LINES_IN_LAMBDA.name, true,\n            mapOf(\"maxLambdaLength\" to \"3\"))\n    )\n\n    @Test\n    @Tag(WarningNames.TOO_MANY_LINES_IN_LAMBDA)\n    fun `less than max`() {\n        lintMethod(\n            \"\"\"\n                    |fun foo() {\n                    |   val x = 10\n                    |   val list = listOf(1, 2, 3, 4, 5)\n                    |       .map {element -> element + x}\n                    |}\n            \"\"\".trimMargin(),\n            rulesConfigList = rulesConfigList\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.TOO_MANY_LINES_IN_LAMBDA)\n    fun `nested lambda with implicit parameter`() {\n        lintMethod(\n            \"\"\"\n                    |fun foo() {\n                    |   private val allTestsFromResources: List<String> by lazy {\n                    |     val fileUrl: URL? = javaClass.getResource(\"123\")\n                    |     val resource = fileUrl\n                    |         ?.let { File(it.file) }\n                    |   }\n                    |}\n            \"\"\".trimMargin(),\n            rulesConfigList = rulesConfigList\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.TOO_MANY_LINES_IN_LAMBDA)\n    fun `lambda doesn't expect parameters`() {\n        lintMethod(\n            \"\"\"\n                    |fun foo() {\n                    |   private val allTestsFromResources: List<String> by lazy {\n                    |     val fileUrl: URL? = javaClass.getResource(\"123\")\n                    |     list = listOf(1, 2, 3, 4, 5)\n                    |         .removeAt(1)\n                    |   }\n                    |}\n            \"\"\".trimMargin(),\n            rulesConfigList = rulesConfigList\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.TOO_MANY_LINES_IN_LAMBDA)\n    fun `less than max without argument`() {\n        lintMethod(\n            \"\"\"\n                    |fun foo() {\n                    |   val x = 10\n                    |   val list = listOf(1, 2, 3, 4, 5)\n                    |       .map {it + x}\n                    |}\n            \"\"\".trimMargin(),\n            rulesConfigList = rulesConfigList\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.TOO_MANY_LINES_IN_LAMBDA)\n    fun `more than max with argument`() {\n        lintMethod(\n            \"\"\"\n                    |fun foo() {\n                    |   val calculateX = { x : Int ->\n                    |       when(x) {\n                    |           in 0..40 -> \"Fail\"\n                    |           in 41..70 -> \"Pass\"\n                    |           in 71..100 -> \"Distinction\"\n                    |           else -> false\n                    |       }\n                    |   }\n                    |}\n            \"\"\".trimMargin(),\n            rulesConfigList = rulesConfigList\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.TOO_MANY_LINES_IN_LAMBDA)\n    fun `more than maximum without argument`() {\n        lintMethod(\n            \"\"\"\n                    |fun foo() {\n                    |   val list = listOf(1, 2, 3, 4, 5)\n                    |       .map {\n                    |           val x = 0\n                    |           val y = x + 1\n                    |           val z = y + 1\n                    |           it + z\n                    |\n                    |\n                    |\n                    |\n                    |   }\n                    |}\n            \"\"\".trimMargin(),\n            DiktatError(3, 13, ruleId, \"${Warnings.TOO_MANY_LINES_IN_LAMBDA.warnText()} max length lambda without arguments is 3, but you have 6\", false),\n            rulesConfigList = rulesConfigList\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.TOO_MANY_LINES_IN_LAMBDA)\n    fun `two lambda more than maximum without argument`() {\n        lintMethod(\n            \"\"\"\n                    |fun foo() {\n                    |   val list = listOf(1, 2, 3, 4, 5)\n                    |       .filter { n -> n % 2 == 1 }\n                    |       .map {\n                    |           val x = 0\n                    |           val y = x + 1\n                    |           val z = y + 1\n                    |           it + z\n                    |\n                    |\n                    |\n                    |\n                    |   }\n                    |}\n            \"\"\".trimMargin(),\n            DiktatError(4, 13, ruleId, \"${Warnings.TOO_MANY_LINES_IN_LAMBDA.warnText()} max length lambda without arguments is 3, but you have 6\", false),\n            rulesConfigList = rulesConfigList\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.TOO_MANY_LINES_IN_LAMBDA)\n    fun `lambda in lambda`() {\n        lintMethod(\n            \"\"\"\n                    |fun foo() {\n                    |   val list = listOf(listOf(1,2,3), listOf(4,5,6))\n                    |       .map {l -> l.map {\n                    |           val x = 0\n                    |           val y = x + 1\n                    |           val z = y + 1\n                    |           println(it)\n                    |           }\n                    |       }\n                    |   }\n            \"\"\".trimMargin(),\n            DiktatError(3, 25, ruleId, \"${Warnings.TOO_MANY_LINES_IN_LAMBDA.warnText()} max length lambda without arguments is 3, but you have 6\", false),\n            rulesConfigList = rulesConfigList\n        )\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/test/kotlin/com/saveourtool/diktat/ruleset/chapter5/LambdaParameterOrderWarnTest.kt",
    "content": "package com.saveourtool.diktat.ruleset.chapter5\n\nimport com.saveourtool.diktat.common.config.rules.DIKTAT_RULE_SET_ID\nimport com.saveourtool.diktat.ruleset.constants.Warnings.LAMBDA_IS_NOT_LAST_PARAMETER\nimport com.saveourtool.diktat.ruleset.rules.chapter5.LambdaParameterOrder\nimport com.saveourtool.diktat.util.LintTestBase\n\nimport com.saveourtool.diktat.api.DiktatError\nimport generated.WarningNames\nimport org.junit.jupiter.api.Tag\nimport org.junit.jupiter.api.Test\n\nclass LambdaParameterOrderWarnTest : LintTestBase(::LambdaParameterOrder) {\n    private val ruleId = \"$DIKTAT_RULE_SET_ID:${LambdaParameterOrder.NAME_ID}\"\n\n    @Test\n    @Tag(WarningNames.LAMBDA_IS_NOT_LAST_PARAMETER)\n    fun `check simple example`() {\n        lintMethod(\n            \"\"\"\n                    |fun foo(a: Int, myLambda: () -> Unit, b: Int) { }\n                    |\n                    |fun foo(a: Int, b: Int, myLambda: () -> Unit) = true\n                    |\n                    |@Suppress(\"LAMBDA_IS_NOT_LAST_PARAMETER\")\n                    |fun foo(a: Int, myLambda: () -> Unit, b: Int) { }\n                    |\n                    |fun foo(a: Int, myLambdab: () -> Unit, myLambda: () -> Unit)\n                    |\n                    |fun foo(a: Int? = null, myLambdab: () -> Unit, myLambda: () -> Unit)\n                    |\n                    |fun foo(lambda1: () -> Unit, lambda2: (() -> Unit)?) {}\n            \"\"\".trimMargin(),\n            DiktatError(1, 17, ruleId, \"${LAMBDA_IS_NOT_LAST_PARAMETER.warnText()} foo\", false)\n        )\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/test/kotlin/com/saveourtool/diktat/ruleset/chapter5/NestedFunctionBlockWarnTest.kt",
    "content": "package com.saveourtool.diktat.ruleset.chapter5\n\nimport com.saveourtool.diktat.common.config.rules.DIKTAT_RULE_SET_ID\nimport com.saveourtool.diktat.common.config.rules.RulesConfig\nimport com.saveourtool.diktat.ruleset.constants.Warnings.NESTED_BLOCK\nimport com.saveourtool.diktat.ruleset.rules.chapter5.NestedFunctionBlock\nimport com.saveourtool.diktat.util.LintTestBase\n\nimport com.saveourtool.diktat.api.DiktatError\nimport generated.WarningNames\nimport org.junit.jupiter.api.Tag\nimport org.junit.jupiter.api.Test\n\nclass NestedFunctionBlockWarnTest : LintTestBase(::NestedFunctionBlock) {\n    private val ruleId = \"$DIKTAT_RULE_SET_ID:${NestedFunctionBlock.NAME_ID}\"\n    private val rulesConfigList = listOf(\n        RulesConfig(NESTED_BLOCK.name, true, mapOf(\"maxNestedBlockQuantity\" to \"2\"))\n    )\n\n    @Test\n    @Tag(WarningNames.NESTED_BLOCK)\n    fun `should ignore lambda expression`() {\n        lintMethod(\n            \"\"\"\n                    |fun foo() {\n                    |   while(true) {\n                    |       println()\n                    |   }\n                    |\n                    |   when(x) {\n                    |       10 -> {10}\n                    |       else -> {\n                    |           if (true) {\n                    |               println(1)\n                    |           }\n                    |       }\n                    |   }\n                    |\n                    |   val x = {\n                    |       if (true) {\n                    |           if (false) {\n                    |               while(false) {\n                    |                   10\n                    |               }\n                    |           }\n                    |       }\n                    |   }\n                    |\n                    |   for(x in 1..2){\n                    |       println(x)\n                    |   }\n                    |}\n            \"\"\".trimMargin()\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.NESTED_BLOCK)\n    fun `check simple nested block`() {\n        lintMethod(\n            \"\"\"\n                    |fun foo() {\n                    |\n                    |   if (true) {\n                    |       if (false) {\n                    |           if (true) {\n                    |               do {\n                    |                   println(\"nested\")\n                    |               } while(true)\n                    |           }\n                    |       }\n                    |   } else {\n                    |       println(\"dscsds\")\n                    |   }\n                    |}\n            \"\"\".trimMargin(),\n            DiktatError(1, 1, ruleId, \"${NESTED_BLOCK.warnText()} foo\", false)\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.NESTED_BLOCK)\n    fun `check simple nested block with try`() {\n        lintMethod(\n            \"\"\"\n                    |fun foo() {\n                    |\n                    |   if (true) {\n                    |       if (false) {\n                    |           try {\n                    |               try{\n                    |                   try{\n                    |\n                    |                   } catch(ex: Exception){\n                    |                       try{\n                    |                           println(\"hi\")\n                    |                       } catch(ex: Exception){}\n                    |                   }\n                    |               } catch(ex: Exception){}\n                    |           } catch(ex: Exception){}\n                    |       }\n                    |   } else {\n                    |       println(\"dscsds\")\n                    |   }\n                    |}\n            \"\"\".trimMargin(),\n            DiktatError(1, 1, ruleId, \"${NESTED_BLOCK.warnText()} foo\", false)\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.NESTED_BLOCK)\n    fun `check simple nested block of function`() {\n        lintMethod(\n            \"\"\"\n                    |fun foo() {\n                    |\n                    |   if (true) {\n                    |       if (false) {\n                    |           fun goo() {\n                    |               if(true) {\n                    |\n                    |               }\n                    |           }\n                    |       }\n                    |   } else {\n                    |       println(\"dscsds\")\n                    |   }\n                    |}\n            \"\"\".trimMargin()\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.NESTED_BLOCK)\n    fun `check simple nested block of local class`() {\n        lintMethod(\n            \"\"\"\n                    |fun foo() {\n                    |   class A() {\n                    |       fun goo() {\n                    |           if (true) {\n                    |               if (false) {\n                    |                   while(true) {\n                    |                       if(false) {\n                    |                           try {\n                    |                               println(\"ne\")\n                    |                           } catch (e: Exception) {}\n                    |                       }\n                    |                   }\n                    |               }\n                    |       } else {\n                    |               println(\"dscsds\")\n                    |           }\n                    |       }\n                    |   }\n                    |   if(true) {\n                    |       while(true) {\n                    |       }\n                    |   }\n                    |}\n            \"\"\".trimMargin(),\n            DiktatError(3, 8, ruleId, \"${NESTED_BLOCK.warnText()} goo\", false)\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.NESTED_BLOCK)\n    fun `check with lambda`() {\n        lintMethod(\n            \"\"\"\n                    private fun findBlocks(node: ASTNode): List<ASTNode> {\n                        val result = mutableListOf<ASTNode>()\n                        node.getChildren(null).forEach {\n                            when (it.elementType) {\n                                IF -> Pair(it.findChildByType(THEN)?.findChildByType(BLOCK), it.findChildByType(ELSE)?.findChildByType(BLOCK))\n                                WHEN -> Pair(it, null)\n                                WHEN_ENTRY -> Pair(it.findChildByType(BLOCK), null)\n                                FUN -> Pair(it.findChildByType(BLOCK), null)\n                                else -> Pair(it.findChildByType(BODY)?.findChildByType(BLOCK), null)\n                            }.let { pair ->\n                                pair.let {\n                                    pair.first?.let { it1 -> result.add(it1) }\n                                    pair.second?.let { it2 -> result.add(it2) }\n                                }\n                            }\n                        }\n                        return result\n                    }\n            \"\"\".trimMargin()\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.NESTED_BLOCK)\n    fun `check with anonymous class`() {\n        lintMethod(\n            \"\"\"\n\n                    val q = list.filter {it == 0}\n\n                    val keyListener = KeyAdapter { keyEvent ->\n                        if (true) {\n                        } else if (false) {\n                            while(true) {\n                                if(true) {\n                                    println(10)\n                                }\n                            }\n                        }\n                    }\n\n                    val keyListener = object : KeyAdapter() {\n                        override fun keyPressed(keyEvent : KeyEvent) {\n                        }\n                    }\n            \"\"\".trimMargin(),\n            DiktatError(4, 50, ruleId, \"${NESTED_BLOCK.warnText()} { keyEvent ->...\", false),\n            rulesConfigList = rulesConfigList\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.NESTED_BLOCK)\n    fun `check simple nested block inside class`() {\n        lintMethod(\n            \"\"\"\n                    |class A {\n                    |   fun foo() {\n                    |       if(true) {\n                    |           if(false) {\n                    |               if(true) {\n                    |                   when(x) {\n                    |                   }\n                    |               }\n                    |           }\n                    |       }\n                    |   }\n                    |\n                    |   fun goo() {\n                    |       if(true){\n                    |           if(false){\n                    |               if(true){\n                    |               }\n                    |           }\n                    |       }\n                    |   }\n                    |}\n            \"\"\".trimMargin(),\n            DiktatError(2, 4, ruleId, \"${NESTED_BLOCK.warnText()} foo\", false)\n        )\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/test/kotlin/com/saveourtool/diktat/ruleset/chapter5/OverloadingArgumentsFunctionWarnTest.kt",
    "content": "package com.saveourtool.diktat.ruleset.chapter5\n\nimport com.saveourtool.diktat.common.config.rules.DIKTAT_RULE_SET_ID\nimport com.saveourtool.diktat.ruleset.constants.Warnings.WRONG_OVERLOADING_FUNCTION_ARGUMENTS\nimport com.saveourtool.diktat.ruleset.rules.chapter5.OverloadingArgumentsFunction\nimport com.saveourtool.diktat.util.LintTestBase\n\nimport com.saveourtool.diktat.api.DiktatError\nimport generated.WarningNames\nimport org.junit.jupiter.api.Tag\nimport org.junit.jupiter.api.Test\n\nclass OverloadingArgumentsFunctionWarnTest : LintTestBase(::OverloadingArgumentsFunction) {\n    private val ruleId = \"$DIKTAT_RULE_SET_ID:${OverloadingArgumentsFunction.NAME_ID}\"\n\n    @Test\n    @Tag(WarningNames.WRONG_OVERLOADING_FUNCTION_ARGUMENTS)\n    fun `check simple example`() {\n        lintMethod(\n            \"\"\"\n                    |fun foo() {}\n                    |\n                    |fun foo(a: Int) {}\n                    |\n                    |fun goo(a: Double) {}\n                    |\n                    |fun goo(a: Float, b: Double) {}\n                    |\n                    |fun goo(b: Float, a: Double, c: Int) {}\n                    |\n                    |@Suppress(\"WRONG_OVERLOADING_FUNCTION_ARGUMENTS\")\n                    |fun goo(a: Float)\n                    |\n                    |fun goo(a: Double? = 0.0) {}\n                    |\n                    |override fun goo() {} // this definitely is not an overload case... why we were treating it as an overload? New diktat rule!\n                    |\n                    |class A {\n                    |   fun foo() {}\n                    |}\n                    |\n                    |abstract class B {\n                    |   abstract fun foo(a: Int) // modifiers are different. This is not related to default arguments. New diktat rule!\n                    |\n                    |   fun foo(){}\n                    |}\n            \"\"\".trimMargin(),\n            DiktatError(1, 1, ruleId, \"${WRONG_OVERLOADING_FUNCTION_ARGUMENTS.warnText()} foo\", false),\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.WRONG_OVERLOADING_FUNCTION_ARGUMENTS)\n    fun `functions with modifiers`() {\n        lintMethod(\n            \"\"\"\n                    |public fun foo() {}\n                    |private fun foo(a: Int) {}\n                    |inline fun foo(a: Int, b: Int) {}\n            \"\"\".trimMargin(),\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.WRONG_OVERLOADING_FUNCTION_ARGUMENTS)\n    fun `functions with override modifiers`() {\n        lintMethod(\n            \"\"\"\n                    |fun list(projectCoordinates: ProjectCoordinates): Flux<FileKey> = list()\n                    |    .filter { it.projectCoordinates == projectCoordinates }\n                    |\n                    |override fun list(): Flux<FileKey> = newFileStorage.list()\n                    |    .map { fileDto ->\n                    |        FileKey(\n                    |            projectCoordinates = fileDto.projectCoordinates,\n                    |            name = fileDto.name,\n                    |            uploadedMillis = fileDto.uploadedTime.toInstant(TimeZone.UTC).toEpochMilliseconds()\n                    |        )\n                    |    }\n            \"\"\".trimMargin(),\n        )\n    }\n    @Test\n    @Tag(WarningNames.WRONG_OVERLOADING_FUNCTION_ARGUMENTS)\n    fun `functions with override modifiers simple`() {\n        lintMethod(\n            \"\"\"\n                    |fun foo(a: Int) {}\n                    |override fun foo() {}\n            \"\"\".trimMargin()\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.WRONG_OVERLOADING_FUNCTION_ARGUMENTS)\n    fun `functions with unordered, but same modifiers`() {\n        lintMethod(\n            \"\"\"\n                    |fun foo(a: Double) {}\n                    |fun foo(a: Double, b: Int) {}\n            \"\"\".trimMargin(),\n            DiktatError(1, 1, ruleId, \"${WRONG_OVERLOADING_FUNCTION_ARGUMENTS.warnText()} foo\", false)\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.WRONG_OVERLOADING_FUNCTION_ARGUMENTS)\n    fun `functions with unordered, but same modifiers and different names`() {\n        lintMethod(\n            \"\"\"\n                    |fun foo(a: Double) {}\n                    |fun foo(b: Double, b: Int) {}\n            \"\"\".trimMargin(),\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.WRONG_OVERLOADING_FUNCTION_ARGUMENTS)\n    fun `check for extensions`() {\n        lintMethod(\n            \"\"\"\n                    private fun isComparisonWithAbs(psiElement: PsiElement) =\n                        when (psiElement) {\n                            is KtBinaryExpression -> psiElement.isComparisonWithAbs()\n                            is KtDotQualifiedExpression -> psiElement.isComparisonWithAbs()\n                            else -> false\n                        }\n\n                    private fun KtBinaryExpression.isComparisonWithAbs() =\n                            takeIf { it.operationToken in comparisonOperators }\n                            ?.run { left as? KtCallExpression ?: right as? KtCallExpression }\n                            ?.run { calleeExpression as? KtNameReferenceExpression }\n                            ?.getReferencedName()\n                            ?.equals(\"abs\")\n                            ?: false\n\n                    private fun KtBinaryExpression.isComparisonWithAbs(a: Int) =\n                            takeIf { it.operationToken in comparisonOperators }\n                            ?.run { left as? KtCallExpression ?: right as? KtCallExpression }\n                            ?.run { calleeExpression as? KtNameReferenceExpression }\n                            ?.getReferencedName()\n                            ?.equals(\"abs\")\n                            ?: false\n\n                    private fun KtBinaryExpression.isComparisonWithAbs(a: Int): Boolean {\n                            return takeIf { it.operationToken in comparisonOperators }\n                            ?.run { left as? KtCallExpression ?: right as? KtCallExpression }\n                            ?.run { calleeExpression as? KtNameReferenceExpression }\n                            ?.getReferencedName()\n                            ?.equals(\"abs\")\n                            ?: false\n                    }\n            \"\"\".trimMargin(),\n            DiktatError(8, 21, ruleId, \"${WRONG_OVERLOADING_FUNCTION_ARGUMENTS.warnText()} isComparisonWithAbs\", false)\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.WRONG_OVERLOADING_FUNCTION_ARGUMENTS)\n    fun `check methods with different return types`() {\n        lintMethod(\n            \"\"\"\n                    private fun KtBinaryExpression.isComparisonWithAbs(a: Int): Boolean {\n                            return takeIf { it.operationToken in comparisonOperators }\n                            ?.run { left as? KtCallExpression ?: right as? KtCallExpression }\n                            ?.run { calleeExpression as? KtNameReferenceExpression }\n                            ?.getReferencedName()\n                            ?.equals(\"abs\")\n                            ?: false\n                    }\n\n                    private fun KtBinaryExpression.isComparisonWithAbs(a: Int): Int {\n                            val q = takeIf { it.operationToken in comparisonOperators }\n                            ?.run { left as? KtCallExpression ?: right as? KtCallExpression }\n                            ?.run { calleeExpression as? KtNameReferenceExpression }\n                            ?.getReferencedName()\n                            ?.equals(\"abs\")\n                            ?: false\n\n                            if (q) return 10\n                            return 11\n                    }\n            \"\"\".trimMargin()\n        )\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/test/kotlin/com/saveourtool/diktat/ruleset/chapter5/ParameterNameInOuterLambdaRuleWarnTest.kt",
    "content": "package com.saveourtool.diktat.ruleset.chapter5\n\nimport com.saveourtool.diktat.common.config.rules.DIKTAT_RULE_SET_ID\nimport com.saveourtool.diktat.common.config.rules.RulesConfig\nimport com.saveourtool.diktat.ruleset.constants.Warnings\nimport com.saveourtool.diktat.ruleset.rules.chapter5.ParameterNameInOuterLambdaRule\nimport com.saveourtool.diktat.util.LintTestBase\n\nimport com.saveourtool.diktat.api.DiktatError\nimport generated.WarningNames\nimport org.junit.jupiter.api.Tag\nimport org.junit.jupiter.api.Test\n\nclass ParameterNameInOuterLambdaRuleWarnTest : LintTestBase(::ParameterNameInOuterLambdaRule) {\n    private val ruleId = \"$DIKTAT_RULE_SET_ID:${ParameterNameInOuterLambdaRule.NAME_ID}\"\n    private val rulesConfigList: List<RulesConfig> = listOf(\n        RulesConfig(Warnings.PARAMETER_NAME_IN_OUTER_LAMBDA.name, true)\n    )\n    private val rulesConfigParameterNameInOuterLambda = listOf(\n        RulesConfig(\n            Warnings.PARAMETER_NAME_IN_OUTER_LAMBDA.name, true, mapOf(\n            \"strictMode\" to \"false\"\n        ))\n    )\n\n    @Test\n    @Tag(WarningNames.PARAMETER_NAME_IN_OUTER_LAMBDA)\n    fun `lambda has specific parameter`() {\n        lintMethod(\n            \"\"\"\n                    |fun foo(lambda: (s: String) -> Unit) {\n                    |   lambda(\"foo\")\n                    |}\n                    |\n                    |fun test() {\n                    |   foo { s ->\n                    |       println(s)\n                    |   }\n                    |}\n            \"\"\".trimMargin(),\n            rulesConfigList = rulesConfigList\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.PARAMETER_NAME_IN_OUTER_LAMBDA)\n    fun `lambda has implicit parameter`() {\n        lintMethod(\n            \"\"\"\n                    |fun foo(lambda: (s: String) -> Unit) {\n                    |   lambda(\"foo\")\n                    |}\n                    |\n                    |fun test() {\n                    |   foo {\n                    |       println(it)\n                    |   }\n                    |}\n            \"\"\".trimMargin(),\n            rulesConfigList = rulesConfigList\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.PARAMETER_NAME_IN_OUTER_LAMBDA)\n    fun `outer lambda and inner lambda have specific parameter`() {\n        lintMethod(\n            \"\"\"\n                    |fun bar(lambda: (s: String) -> Unit) {\n                    |   lambda(\"bar\")\n                    |}\n                    |\n                    |fun foo(lambda: (s: String) -> Unit) {\n                    |   lambda(\"foo\")\n                    |}\n                    |\n                    |fun test() {\n                    |   foo { f ->\n                    |       bar { b ->\n                    |           println(f + \" -> \" + b)\n                    |       }\n                    |   }\n                    |}\n            \"\"\".trimMargin(),\n            rulesConfigList = rulesConfigList\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.PARAMETER_NAME_IN_OUTER_LAMBDA)\n    fun `outer lambda has specific parameter but inner lambda has implicit parameter`() {\n        lintMethod(\n            \"\"\"\n                    |fun bar(lambda: (s: String) -> Unit) {\n                    |   lambda(\"bar\")\n                    |}\n                    |\n                    |fun foo(lambda: (s: String) -> Unit) {\n                    |   lambda(\"foo\")\n                    |}\n                    |\n                    |fun test() {\n                    |   foo { f ->\n                    |       bar {\n                    |           println(f + \" -> \" + it)\n                    |       }\n                    |   }\n                    |}\n            \"\"\".trimMargin(),\n            rulesConfigList = rulesConfigList\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.PARAMETER_NAME_IN_OUTER_LAMBDA)\n    fun `outer lambda has implicit parameter but inner lambda has specific parameter`() {\n        lintMethod(\n            \"\"\"\n                    |fun bar(lambda: (s: String) -> Unit) {\n                    |   lambda(\"bar\")\n                    |}\n                    |\n                    |fun foo(lambda: (s: String) -> Unit) {\n                    |   lambda(\"foo\")\n                    |}\n                    |\n                    |fun test() {\n                    |   foo {\n                    |       bar { b ->\n                    |           println(it + \" -> \" + b)\n                    |       }\n                    |   }\n                    |}\n            \"\"\".trimMargin(),\n            DiktatError(10, 8, ruleId, \"${Warnings.PARAMETER_NAME_IN_OUTER_LAMBDA.warnText()} lambda without arguments has inner lambda\", false),\n            rulesConfigList = rulesConfigList\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.PARAMETER_NAME_IN_OUTER_LAMBDA)\n    fun `outer lambda has implicit parameter but inner lambda has no parameter`() {\n        lintMethod(\n            \"\"\"\n                    |fun bar(lambda: () -> Unit) {\n                    |   lambda()\n                    |}\n                    |\n                    |fun foo(lambda: (s: String) -> Unit) {\n                    |   lambda(\"foo\")\n                    |}\n                    |\n                    |fun test() {\n                    |   foo {\n                    |       bar {\n                    |           println(it + \" -> bar\")\n                    |       }\n                    |   }\n                    |}\n            \"\"\".trimMargin(),\n            rulesConfigList = rulesConfigList\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.PARAMETER_NAME_IN_OUTER_LAMBDA)\n    fun `outer lambda has no parameter but inner lambda has implicit parameter`() {\n        lintMethod(\n            \"\"\"\n                    |fun bar(lambda: (s: String) -> Unit) {\n                    |   lambda(\"bar\")\n                    |}\n                    |\n                    |fun foo(lambda: () -> Unit) {\n                    |   lambda()\n                    |}\n                    |\n                    |fun test() {\n                    |   foo {\n                    |       bar {\n                    |           println(\"foo -> \" + it)\n                    |       }\n                    |   }\n                    |}\n            \"\"\".trimMargin(),\n            rulesConfigList = rulesConfigList\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.PARAMETER_NAME_IN_OUTER_LAMBDA)\n    fun `shouldn't warn if nested lambda has explicit it`() {\n        lintMethod(\n            \"\"\"\n                |fun test() {\n                |    run {\n                |        l.map { it ->\n                |            println(it)\n                |        }\n                |    }\n                |}\n            \"\"\".trimMargin(),\n            rulesConfigList = rulesConfigList\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.PARAMETER_NAME_IN_OUTER_LAMBDA)\n    fun `lambdas at the same level`() {\n        lintMethod(\n            \"\"\"\n                |fun testA() {\n                |   val overrideFunctions: List <Int> = emptyList()\n                |   overrideFunctions.forEach { functionNameMap.compute(it.getIdentifierName()!!.text) { _, oldValue -> (oldValue ?: 0) + 1 } }\n                |}\n                \"\"\".trimMargin(),\n            rulesConfigList = this.rulesConfigParameterNameInOuterLambda\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.PARAMETER_NAME_IN_OUTER_LAMBDA)\n    fun `lambdas at the same level 2`() {\n        lintMethod(\n            \"\"\"\n                |private fun isCheckNeeded(whiteSpace: PsiWhiteSpace) =\n                |    whiteSpace.parent\n                |        .node\n                |        .elementType\n                |        .let { it == VALUE_PARAMETER_LIST || it == VALUE_ARGUMENT_LIST } &&\n                |            whiteSpace.siblings(forward = false, withItself = false).none { it is PsiWhiteSpace && it.textContains('\\n') } &&\n                |            whiteSpace.siblings(forward = true, withItself = false).any {\n                |                it.node.elementType.run { this == VALUE_ARGUMENT || this == VALUE_PARAMETER }\n                |            }\n                \"\"\".trimMargin(),\n            rulesConfigList = this.rulesConfigParameterNameInOuterLambda\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.PARAMETER_NAME_IN_OUTER_LAMBDA)\n    fun `lambdas at the same level 21`() {\n        lintMethod(\n            \"\"\"\n                |private fun isCheckNeeded(w: PsiWhiteSpace, h: PsiWhiteSpace) =\n                |    w.let { it == VALUE_PARAMETER_LIST || it == VALUE_ARGUMENT_LIST } &&\n                |            h.none { it is PsiWhiteSpace && it.textContains('\\n') } &&\n                |            h.any {\n                |                it.node.elementType.run { this == VALUE_ARGUMENT || this == VALUE_PARAMETER }\n                |            }\n                \"\"\".trimMargin(),\n            rulesConfigList = this.rulesConfigParameterNameInOuterLambda\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.PARAMETER_NAME_IN_OUTER_LAMBDA)\n    fun `lambdas at the same level 3`() {\n        lintMethod(\n            \"\"\"\n                |private fun checkBlankLineAfterKdoc(node: ASTNode) {\n                |    commentType.forEach {\n                |        val kdoc = node.getFirstChildWithType(it)\n                |        kdoc?.treeNext?.let { nodeAfterKdoc ->\n                |            if (nodeAfterKdoc.elementType == WHITE_SPACE && nodeAfterKdoc.numNewLines() > 1) {\n                |                WRONG_NEWLINES_AROUND_KDOC.warnAndFix(configRules, emitWarn, isFixMode, \"redundant blank line after ${'$'}{kdoc.text}\", nodeAfterKdoc.startOffset, nodeAfterKdoc) {\n                |                    nodeAfterKdoc.leaveOnlyOneNewLine()\n                |                }\n                |            }\n                |        }\n                |    }\n                |}\n                \"\"\".trimMargin(),\n            rulesConfigList = this.rulesConfigParameterNameInOuterLambda\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.PARAMETER_NAME_IN_OUTER_LAMBDA)\n    fun `lambdas at the same level 4`() {\n        lintMethod(\n            \"\"\"\n                |private fun KSAnnotation.getArgumentValue(argumentName: String): String = arguments\n                |    .singleOrNull { it.name?.asString() == argumentName }\n                |    .let {\n                |        requireNotNull(it) {\n                |            \"Not found ${'$'}argumentName in ${'$'}this\"\n                |        }\n                |    }\n                |    .value\n                |    ?.let { it as? String }\n                |    .let {\n                |        requireNotNull(it) {\n                |            \"Not found a value for ${'$'}argumentName in ${'$'}this\"\n                |        }\n                |    }\n                \"\"\".trimMargin(),\n            rulesConfigList = this.rulesConfigParameterNameInOuterLambda\n        )\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/test/kotlin/com/saveourtool/diktat/ruleset/chapter6/AbstractClassesFixTest.kt",
    "content": "package com.saveourtool.diktat.ruleset.chapter6\n\nimport com.saveourtool.diktat.ruleset.rules.chapter6.classes.AbstractClassesRule\nimport com.saveourtool.diktat.util.FixTestBase\n\nimport generated.WarningNames.CLASS_SHOULD_NOT_BE_ABSTRACT\nimport org.junit.jupiter.api.Tag\nimport org.junit.jupiter.api.Test\n\nclass AbstractClassesFixTest : FixTestBase(\"test/chapter6/abstract_classes\", ::AbstractClassesRule) {\n    @Test\n    @Tag(CLASS_SHOULD_NOT_BE_ABSTRACT)\n    fun `fix abstract class`() {\n        fixAndCompare(\"ShouldReplaceAbstractKeywordExpected.kt\", \"ShouldReplaceAbstractKeywordTest.kt\")\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/test/kotlin/com/saveourtool/diktat/ruleset/chapter6/AbstractClassesWarnTest.kt",
    "content": "package com.saveourtool.diktat.ruleset.chapter6\n\nimport com.saveourtool.diktat.common.config.rules.DIKTAT_RULE_SET_ID\nimport com.saveourtool.diktat.ruleset.constants.Warnings\nimport com.saveourtool.diktat.ruleset.rules.chapter6.classes.AbstractClassesRule\nimport com.saveourtool.diktat.util.LintTestBase\n\nimport com.saveourtool.diktat.api.DiktatError\nimport generated.WarningNames.CLASS_SHOULD_NOT_BE_ABSTRACT\nimport org.junit.jupiter.api.Tag\nimport org.junit.jupiter.api.Test\n\nclass AbstractClassesWarnTest : LintTestBase(::AbstractClassesRule) {\n    private val ruleId = \"$DIKTAT_RULE_SET_ID:${AbstractClassesRule.NAME_ID}\"\n\n    @Test\n    @Tag(CLASS_SHOULD_NOT_BE_ABSTRACT)\n    fun `should not replace abstract with open`() {\n        lintMethod(\n            \"\"\"\n                |abstract class Some(val a: Int = 5) {\n                |   abstract fun func() {}\n                |\n                |   fun another() {}\n                |}\n            \"\"\".trimMargin()\n        )\n    }\n\n    @Test\n    @Tag(CLASS_SHOULD_NOT_BE_ABSTRACT)\n    fun `should replace abstract on open`() {\n        lintMethod(\n            \"\"\"\n                |abstract class Some(val a: Int = 5) {\n                |    fun func() {}\n                |}\n            \"\"\".trimMargin(),\n            DiktatError(1, 37, ruleId, \"${Warnings.CLASS_SHOULD_NOT_BE_ABSTRACT.warnText()} Some\", true)\n        )\n    }\n\n    @Test\n    @Tag(CLASS_SHOULD_NOT_BE_ABSTRACT)\n    fun `should replace abstract on open with inner`() {\n        lintMethod(\n            \"\"\"\n                |class Some(val a: Int = 5) {\n                |    fun func() {}\n                |\n                |    inner abstract class Inner {\n                |       fun another()\n                |    }\n                |}\n            \"\"\".trimMargin(),\n            DiktatError(4, 32, ruleId, \"${Warnings.CLASS_SHOULD_NOT_BE_ABSTRACT.warnText()} Inner\", true)\n        )\n    }\n\n    @Test\n    @Tag(CLASS_SHOULD_NOT_BE_ABSTRACT)\n    fun `should replace abstract on open in actual or expect classes`() {\n        lintMethod(\n            \"\"\"\n                |actual abstract class CoroutineTest actual constructor() {\n                |    /**\n                |     * Test rule\n                |     */\n                |    @get:Rule\n                |    var coroutineTestRule = CoroutineTestRule()\n                |\n                |    /**\n                |     * Run test\n                |     *\n                |     * @param T\n                |     * @param block\n                |     * @receiver a Coroutine Scope\n                |     */\n                |    actual fun <T> runTest(block: suspend CoroutineScope.() -> T) {\n                |       runBlocking {\n                |       block()\n                |       }\n                |    }\n                |}\n            \"\"\".trimMargin(),\n            DiktatError(1, 58, ruleId, \"${Warnings.CLASS_SHOULD_NOT_BE_ABSTRACT.warnText()} CoroutineTest\", true)\n        )\n    }\n\n    @Test\n    @Tag(CLASS_SHOULD_NOT_BE_ABSTRACT)\n    fun `should not remove abstract on class if there are only abstract properties`() {\n        lintMethod(\n            \"\"\"\n                |abstract class BaseUsesProcessor() {\n                |    // Store uses by file\n                |    abstract val a: String\n                |\n                |    fun foo() {}\n                |}\n            \"\"\".trimMargin()\n        )\n    }\n\n    @Test\n    @Tag(CLASS_SHOULD_NOT_BE_ABSTRACT)\n    fun `should not trigger on classes that extend other classes`() {\n        lintMethod(\n            \"\"\"\n                |abstract class Example: Base() {\n                |    fun foo() {}\n                |}\n            \"\"\".trimMargin()\n        )\n    }\n\n    @Test\n    @Tag(CLASS_SHOULD_NOT_BE_ABSTRACT)\n    fun `should not trigger on classes that implement interfaces`() {\n        lintMethod(\n            \"\"\"\n                |abstract class Example: Base {\n                |    fun foo() {}\n                |}\n            \"\"\".trimMargin(),\n        )\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/test/kotlin/com/saveourtool/diktat/ruleset/chapter6/AvoidUtilityClassWarnTest.kt",
    "content": "package com.saveourtool.diktat.ruleset.chapter6\n\nimport com.saveourtool.diktat.common.config.rules.DIKTAT_RULE_SET_ID\nimport com.saveourtool.diktat.ruleset.constants.Warnings.AVOID_USING_UTILITY_CLASS\nimport com.saveourtool.diktat.ruleset.rules.chapter6.AvoidUtilityClass\nimport com.saveourtool.diktat.util.LintTestBase\n\nimport com.saveourtool.diktat.api.DiktatError\nimport generated.WarningNames\nimport org.junit.jupiter.api.Tag\nimport org.junit.jupiter.api.Test\nimport org.junit.jupiter.api.io.TempDir\nimport java.nio.file.Path\n\nclass AvoidUtilityClassWarnTest : LintTestBase(::AvoidUtilityClass) {\n    private val ruleId = \"$DIKTAT_RULE_SET_ID:${AvoidUtilityClass.NAME_ID}\"\n\n    @Test\n    @Tag(WarningNames.AVOID_USING_UTILITY_CLASS)\n    fun `simple test`() {\n        lintMethod(\n            \"\"\"\n                    |object StringUtil {\n                    |   fun stringInfo(myString: String): Int {\n                    |       return myString.count{ \"something\".contains(it) }\n                    |   }\n                    |}\n                    |\n                    |class A() {\n                    |   fun foo() { }\n                    |}\n                    |\n                    |class StringUtils {\n                    |   fun goo(tex: String): Int {\n                    |       return myString.count{ \"something\".contains(it) }\n                    |   }\n                    |}\n                    |\n                    |class StringUtil {\n                    |   val z = \"hello\"\n                    |   fun goo(tex: String): Int {\n                    |       return myString.count{ \"something\".contains(it) }\n                    |   }\n                    |}\n            \"\"\".trimMargin(),\n            DiktatError(1, 1, ruleId, \"${AVOID_USING_UTILITY_CLASS.warnText()} StringUtil\"),\n            DiktatError(11, 1, ruleId, \"${AVOID_USING_UTILITY_CLASS.warnText()} StringUtils\")\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.AVOID_USING_UTILITY_CLASS)\n    fun `test with comment anf companion`() {\n        lintMethod(\n            \"\"\"\n                    |\n                    |class StringUtils {\n                    |   companion object  {\n                    |       private val name = \"Hello\"\n                    |   }\n                    |   /**\n                    |    * @param tex\n                    |    */\n                    |   fun goo(tex: String): Int {\n                    |       //hehe\n                    |       return myString.count{ \"something\".contains(it) }\n                    |   }\n                    |}\n                    |\n                    |class StringUtil {\n                    |   /*\n                    |\n                    |    */\n                    |   companion object  {\n                    |   }\n                    |   val z = \"hello\"\n                    |   fun goo(tex: String): Int {\n                    |       return myString.count{ \"something\".contains(it) }\n                    |   }\n                    |}\n            \"\"\".trimMargin(),\n            DiktatError(2, 1, ruleId, \"${AVOID_USING_UTILITY_CLASS.warnText()} StringUtils\")\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.AVOID_USING_UTILITY_CLASS)\n    fun `test with class without identifier`() {\n        lintMethod(\n            \"\"\"\n                    fun foo() {\n                        window.addMouseListener(object : MouseAdapter() {\n                            override fun mouseClicked(e: MouseEvent) { /*...*/ }\n\n                            override fun mouseEntered(e: MouseEvent) { /*...*/ }\n                        })\n                    }\n            \"\"\".trimMargin()\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.AVOID_USING_UTILITY_CLASS)\n    fun `check test-class`(@TempDir tempDir: Path) {\n        lintMethodWithFile(\n            \"\"\"\n                    |class StringUtils {\n                    |   fun goo(tex: String): Int {\n                    |       return myString.count{ \"something\".contains(it) }\n                    |   }\n                    |}\n            \"\"\".trimMargin(),\n            tempDir = tempDir,\n            fileName = \"src/main/kotlin/com/saveourtool/diktat/Example.kt\",\n            DiktatError(1, 1, ruleId, \"${AVOID_USING_UTILITY_CLASS.warnText()} StringUtils\"),\n        )\n        lintMethodWithFile(\n            \"\"\"\n                    |@Test\n                    |class StringUtils1 {\n                    |   fun goo(tex: String): Int {\n                    |       return myString.count{ \"something\".contains(it) }\n                    |   }\n                    |}\n            \"\"\".trimMargin(),\n            tempDir = tempDir,\n            fileName = \"src/test/kotlin/com/saveourtool/diktat/Example.kt\"\n        )\n        lintMethodWithFile(\n            \"\"\"\n                    |class StringUtils2 {\n                    |   fun goo(tex: String): Int {\n                    |       return myString.count{ \"something\".contains(it) }\n                    |   }\n                    |}\n            \"\"\".trimMargin(),\n            tempDir = tempDir,\n            fileName = \"src/test/kotlin/com/saveourtool/diktat/UtilTest.kt\"\n        )\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/test/kotlin/com/saveourtool/diktat/ruleset/chapter6/CompactInitializationFixTest.kt",
    "content": "package com.saveourtool.diktat.ruleset.chapter6\n\nimport com.saveourtool.diktat.ruleset.rules.chapter6.classes.CompactInitialization\nimport com.saveourtool.diktat.util.FixTestBase\n\nimport generated.WarningNames\nimport org.junit.jupiter.api.Tag\nimport org.junit.jupiter.api.Test\n\nclass CompactInitializationFixTest : FixTestBase(\"test/chapter6/compact_initialization\", ::CompactInitialization) {\n    @Test\n    @Tag(WarningNames.COMPACT_OBJECT_INITIALIZATION)\n    fun `should wrap properties into apply`() {\n        fixAndCompare(\"SimpleExampleExpected.kt\", \"SimpleExampleTest.kt\")\n    }\n\n    @Test\n    @Tag(WarningNames.COMPACT_OBJECT_INITIALIZATION)\n    fun `should wrap properties into apply also moving comments`() {\n        fixAndCompare(\"ExampleWithCommentsExpected.kt\", \"ExampleWithCommentsTest.kt\")\n    }\n\n    @Test\n    @Tag(WarningNames.COMPACT_OBJECT_INITIALIZATION)\n    fun `should wrap properties into apply - existing apply with value argument`() {\n        fixAndCompare(\"ApplyWithValueArgumentExpected.kt\", \"ApplyWithValueArgumentTest.kt\")\n    }\n\n    @Test\n    @Tag(WarningNames.COMPACT_OBJECT_INITIALIZATION)\n    fun `should not move statements with this keyword into apply block`() {\n        fixAndCompare(\"ApplyOnStatementsWithThisKeywordExpected.kt\", \"ApplyOnStatementsWithThisKeywordTest.kt\")\n    }\n\n    @Test\n    @Tag(WarningNames.COMPACT_OBJECT_INITIALIZATION)\n    fun `should rename field in apply block to this keyword`() {\n        fixAndCompare(\"StatementUseFieldMultipleTimesExpected.kt\", \"StatementUseFieldMultipleTimesTest.kt\")\n    }\n\n    @Test\n    @Tag(WarningNames.COMPACT_OBJECT_INITIALIZATION)\n    fun `should wrap receiver in parentheses if required`() {\n        fixAndCompare(\"ParenthesizedReceiverExpected.kt\", \"ParenthesizedReceiverTest.kt\")\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/test/kotlin/com/saveourtool/diktat/ruleset/chapter6/CompactInitializationWarnTest.kt",
    "content": "package com.saveourtool.diktat.ruleset.chapter6\n\nimport com.saveourtool.diktat.common.config.rules.DIKTAT_RULE_SET_ID\nimport com.saveourtool.diktat.ruleset.constants.Warnings.COMPACT_OBJECT_INITIALIZATION\nimport com.saveourtool.diktat.ruleset.rules.chapter6.classes.CompactInitialization\nimport com.saveourtool.diktat.util.LintTestBase\n\nimport com.saveourtool.diktat.api.DiktatError\nimport generated.WarningNames\nimport org.junit.jupiter.api.Tag\nimport org.junit.jupiter.api.Test\n\nclass CompactInitializationWarnTest : LintTestBase(::CompactInitialization) {\n    private val ruleId = \"$DIKTAT_RULE_SET_ID:${CompactInitialization.NAME_ID}\"\n\n    @Test\n    @Tag(WarningNames.COMPACT_OBJECT_INITIALIZATION)\n    fun `compact class instantiation - positive example`() {\n        lintMethod(\n            \"\"\"\n                |fun main() {\n                |    val httpClient = HttpClient(\"myConnection\")\n                |            .apply {\n                |                url = \"http://example.com\"\n                |                port = \"8080\"\n                |                timeout = 100\n                |            }\n                |    httpClient.doRequest()\n                |}\n            \"\"\".trimMargin()\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.COMPACT_OBJECT_INITIALIZATION)\n    fun `should suggest compact class instantiation`() {\n        lintMethod(\n            \"\"\"\n                |fun main() {\n                |    val httpClient = HttpClient(\"myConnection\")\n                |    httpClient.url = \"http://example.com\"\n                |    httpClient.port = \"8080\"\n                |    httpClient.timeout = 100\n                |    httpClient.doRequest()\n                |}\n            \"\"\".trimMargin(),\n            DiktatError(3, 5, ruleId, \"${COMPACT_OBJECT_INITIALIZATION.warnText()} url\", true),\n            DiktatError(4, 5, ruleId, \"${COMPACT_OBJECT_INITIALIZATION.warnText()} port\", true),\n            DiktatError(5, 5, ruleId, \"${COMPACT_OBJECT_INITIALIZATION.warnText()} timeout\", true),\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.COMPACT_OBJECT_INITIALIZATION)\n    fun `should suggest compact class instantiation - with comments`() {\n        lintMethod(\n            \"\"\"\n                |fun main() {\n                |    val httpClient = HttpClient(\"myConnection\")\n                |    // setting url for http requests\n                |    httpClient.url = \"http://example.com\"\n                |    // setting port\n                |    httpClient.port = \"8080\"\n                |\n                |    // setting timeout to 100\n                |    httpClient.timeout = 100\n                |    httpClient.doRequest()\n                |}\n            \"\"\".trimMargin(),\n            DiktatError(4, 5, ruleId, \"${COMPACT_OBJECT_INITIALIZATION.warnText()} url\", true),\n            DiktatError(6, 5, ruleId, \"${COMPACT_OBJECT_INITIALIZATION.warnText()} port\", true),\n            DiktatError(9, 5, ruleId, \"${COMPACT_OBJECT_INITIALIZATION.warnText()} timeout\", true),\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.COMPACT_OBJECT_INITIALIZATION)\n    fun `class instantiation partially in apply`() {\n        lintMethod(\n            \"\"\"\n                |fun main() {\n                |    val httpClient = HttpClient(\"myConnection\")\n                |            .apply {\n                |                url = \"http://example.com\"\n                |                port = \"8080\"\n                |            }\n                |    httpClient.timeout = 100\n                |    httpClient.doRequest()\n                |}\n            \"\"\".trimMargin(),\n            DiktatError(7, 5, ruleId, \"${COMPACT_OBJECT_INITIALIZATION.warnText()} timeout\", true)\n        )\n    }\n\n    // Creating the `apply` block here breaks the compilation\n    @Test\n    @Tag(WarningNames.COMPACT_OBJECT_INITIALIZATION)\n    fun `should not trigger to infix function 1`() {\n        lintMethod(\n            \"\"\"\n                |fun foo(line: String) = line\n                |    .split(\",\", \", \")\n                |    .associate {\n                |        val pair = it.split(\"=\", limit = 2).map {\n                |            it.replace(\"\\\\=\", \"=\")\n                |        }\n                |        pair.first() to pair.last()\n                |    }\n            \"\"\".trimMargin(),\n        )\n    }\n\n    // Apply block doesn't break the compilation, however such changes can break the user logic\n    @Test\n    @Tag(WarningNames.COMPACT_OBJECT_INITIALIZATION)\n    fun `should not trigger to infix function 2`() {\n        lintMethod(\n            \"\"\"\n                |fun foo(line: String) {\n                |    val pair = line.split(\"=\", limit = 2).map {\n                |        it.replace(\"\\\\=\", \"=\")\n                |    }\n                |    pair.first() to pair.last()\n                |}\n            \"\"\".trimMargin(),\n        )\n    }\n\n    // For generality don't trigger on any infix function, despite the fact, that with apply block all will be okay\n    @Test\n    @Tag(WarningNames.COMPACT_OBJECT_INITIALIZATION)\n    fun `should not trigger to infix function 3`() {\n        lintMethod(\n            \"\"\"\n                |fun `translate text`() {\n                |    val res = translateText(text = \"dummy\")\n                |    (res is TranslationsSuccess) shouldBe true\n                |    val translationsSuccess = res as TranslationsSuccess\n                |    translationsSuccess.translations shouldHaveSize 1\n                |}\n            \"\"\".trimMargin(),\n        )\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/test/kotlin/com/saveourtool/diktat/ruleset/chapter6/CustomGetterSetterWarnTest.kt",
    "content": "package com.saveourtool.diktat.ruleset.chapter6\n\nimport com.saveourtool.diktat.common.config.rules.DIKTAT_RULE_SET_ID\nimport com.saveourtool.diktat.ruleset.constants.Warnings\nimport com.saveourtool.diktat.ruleset.rules.chapter6.CustomGetterSetterRule\nimport com.saveourtool.diktat.util.LintTestBase\n\nimport com.saveourtool.diktat.api.DiktatError\nimport generated.WarningNames.CUSTOM_GETTERS_SETTERS\nimport org.junit.jupiter.api.Tag\nimport org.junit.jupiter.api.Test\n\nclass CustomGetterSetterWarnTest : LintTestBase(::CustomGetterSetterRule) {\n    private val ruleId = \"$DIKTAT_RULE_SET_ID:${CustomGetterSetterRule.NAME_ID}\"\n\n    @Test\n    @Tag(CUSTOM_GETTERS_SETTERS)\n    fun `no custom getters and setters allowed`() {\n        lintMethod(\n            \"\"\"\n                    |class A {\n                    |    var size: Int = 0\n                    |        set(value) {\n                    |            println(\"Side effect\")\n                    |            field = value\n                    |        }\n                    |        get() = this.hashCode() * 2\n                    |}\n            \"\"\".trimMargin(),\n            DiktatError(3, 9, ruleId, \"${Warnings.CUSTOM_GETTERS_SETTERS.warnText()} set\"),\n            DiktatError(7, 9, ruleId, \"${Warnings.CUSTOM_GETTERS_SETTERS.warnText()} get\"),\n        )\n    }\n\n    @Test\n    @Tag(CUSTOM_GETTERS_SETTERS)\n    fun `no custom getters allowed`() {\n        lintMethod(\n            \"\"\"\n                    |class A {\n                    |\n                    |        fun set(value) {\n                    |            println(\"Side effect\")\n                    |        }\n                    |\n                    |        fun get() = 47\n                    |}\n            \"\"\".trimMargin(),\n        )\n    }\n\n    @Test\n    @Tag(CUSTOM_GETTERS_SETTERS)\n    fun `override getter`() {\n        lintMethod(\n            \"\"\"\n                    |interface A {\n                    |    val a: Int\n                    |}\n                    |\n                    |object B: A {\n                    |    override val a: int\n                    |        get() = 0\n                    |}\n            \"\"\".trimMargin(),\n        )\n    }\n\n    @Test\n    @Tag(CUSTOM_GETTERS_SETTERS)\n    fun `exception case with private setter`() {\n        lintMethod(\n            \"\"\"\n                    |class A {\n                    |    var size: Int = 0\n                    |        private set(value) {\n                    |            println(\"Side effect\")\n                    |            field = value\n                    |        }\n                    |        get() = this.hashCode() * 2\n                    |}\n            \"\"\".trimMargin(),\n            DiktatError(7, 9, ruleId, \"${Warnings.CUSTOM_GETTERS_SETTERS.warnText()} get\"),\n        )\n    }\n\n    @Test\n    @Tag(CUSTOM_GETTERS_SETTERS)\n    fun `exception case with protected setter`() {\n        lintMethod(\n            \"\"\"\n                    |class A {\n                    |    var size: Int = 0\n                    |        protected set(value) {\n                    |            println(\"Side effect\")\n                    |            field = value\n                    |        }\n                    |        get() = this.hashCode() * 2\n                    |}\n            \"\"\".trimMargin(),\n            DiktatError(3, 19, ruleId, \"${Warnings.CUSTOM_GETTERS_SETTERS.warnText()} set\"),\n            DiktatError(7, 9, ruleId, \"${Warnings.CUSTOM_GETTERS_SETTERS.warnText()} get\"),\n        )\n    }\n\n    @Test\n    @Tag(CUSTOM_GETTERS_SETTERS)\n    fun `should not trigger on property with backing field`() {\n        lintMethod(\n            \"\"\"\n                    |package com.example\n                    |\n                    |class MutableTableContainer {\n                    |   private var _table: Map<String, Int>? = null\n                    |\n                    |   val table: Map<String, Int>\n                    |       get() {\n                    |           if (_table == null) {\n                    |               _table = hashMapOf()\n                    |           }\n                    |           return _table ?: throw AssertionError(\"Set to null by another thread\")\n                    |       }\n                    |       set(value) {\n                    |           field = value\n                    |       }\n                    |\n                    |}\n            \"\"\".trimMargin(),\n        )\n    }\n\n    @Test\n    @Tag(CUSTOM_GETTERS_SETTERS)\n    fun `should trigger on backing field with setter`() {\n        val code =\n            \"\"\"\n                    |package com.example\n                    |\n                    |class MutableTableContainer {\n                    |   var _table: Map<String, Int>? = null\n                    |                set(value) {\n                    |                    field = value\n                    |                }\n                    |\n                    |   val table: Map<String, Int>\n                    |       get() {\n                    |           if (_table == null) {\n                    |               _table = hashMapOf()\n                    |           }\n                    |           return _table ?: throw AssertionError(\"Set to null by another thread\")\n                    |       }\n                    |       set(value) {\n                    |           field = value\n                    |       }\n                    |\n                    |}\n            \"\"\".trimMargin()\n        lintMethod(code,\n            DiktatError(5, 17, ruleId, \"${Warnings.CUSTOM_GETTERS_SETTERS.warnText()} set\", false),\n            DiktatError(10, 8, ruleId, \"${Warnings.CUSTOM_GETTERS_SETTERS.warnText()} get\", false),\n            DiktatError(16, 8, ruleId, \"${Warnings.CUSTOM_GETTERS_SETTERS.warnText()} set\", false)\n        )\n    }\n}\n\n"
  },
  {
    "path": "diktat-rules/src/test/kotlin/com/saveourtool/diktat/ruleset/chapter6/DataClassesRuleWarnTest.kt",
    "content": "package com.saveourtool.diktat.ruleset.chapter6\n\nimport com.saveourtool.diktat.common.config.rules.DIKTAT_RULE_SET_ID\nimport com.saveourtool.diktat.ruleset.constants.Warnings\nimport com.saveourtool.diktat.ruleset.rules.chapter6.classes.DataClassesRule\nimport com.saveourtool.diktat.util.LintTestBase\n\nimport com.saveourtool.diktat.api.DiktatError\nimport generated.WarningNames.USE_DATA_CLASS\nimport org.junit.jupiter.api.Tag\nimport org.junit.jupiter.api.Test\n\nclass DataClassesRuleWarnTest : LintTestBase(::DataClassesRule) {\n    private val ruleId = \"$DIKTAT_RULE_SET_ID:${DataClassesRule.NAME_ID}\"\n\n    @Test\n    @Tag(USE_DATA_CLASS)\n    fun `trigger on default class`() {\n        lintMethod(\n            \"\"\"\n                    |class Some(val a: Int = 5) {\n                    |\n                    |}\n            \"\"\".trimMargin(),\n            DiktatError(1, 1, ruleId, \"${Warnings.USE_DATA_CLASS.warnText()} Some\")\n        )\n    }\n\n    @Test\n    @Tag(USE_DATA_CLASS)\n    fun `_regression_ trigger on default class without a body`() {\n        lintMethod(\n            \"\"\"\n                    |class Some(val a: Int = 5)\n                    |\n            \"\"\".trimMargin(),\n            DiktatError(1, 1, ruleId, \"${Warnings.USE_DATA_CLASS.warnText()} Some\")\n        )\n    }\n\n    @Test\n    @Tag(USE_DATA_CLASS)\n    fun `should trigger - dont forget to consider this class in fix`() {\n        lintMethod(\n            \"\"\"\n                    |class Test {\n                    |   var a: Int = 0\n                    |          get() = field\n                    |          set(value: Int) { field = value}\n                    |}\n            \"\"\".trimMargin(),\n            DiktatError(1, 1, ruleId, \"${Warnings.USE_DATA_CLASS.warnText()} Test\")\n        )\n    }\n\n    @Test\n    @Tag(USE_DATA_CLASS)\n    fun `should not trigger if there is some logic in accessor`() {\n        lintMethod(\n            \"\"\"\n                    |class Test {\n                    |   var a: Int = 0\n                    |          get() = field\n                    |          set(value: Int) {\n                    |              field = value\n                    |              someFun(value)\n                    |          }\n                    |}\n            \"\"\".trimMargin()\n        )\n    }\n\n    @Test\n    @Tag(USE_DATA_CLASS)\n    fun `should not trigger on class with bad modifiers`() {\n        lintMethod(\n            \"\"\"\n                    |data class Some(val a: Int = 5) {\n                    |\n                    |}\n                    |\n                    |abstract class Another() {}\n                    |\n                    |open class Open(){}\n                    |\n                    |sealed class Clazz{}\n                    |\n                    |data class CheckInner {\n                    |   inner class Inner {}\n                    |}\n                    |\n                    |enum class Num {\n                    |\n                    |}\n            \"\"\".trimMargin()\n        )\n    }\n\n    @Test\n    @Tag(USE_DATA_CLASS)\n    fun `should not trigger on classes with functions`() {\n        lintMethod(\n            \"\"\"\n                    |class Some {\n                    |   val prop = 5\n                    |   private fun someFunc() {}\n                    |}\n            \"\"\".trimMargin()\n        )\n    }\n\n    @Test\n    @Tag(USE_DATA_CLASS)\n    fun `should not trigger on classes with no property in constructor`() {\n        lintMethod(\n            \"\"\"\n                    |class B(map: Map<Int,Int>) {}\n                    |\n                    |class Ab(val map: Map<Int, Int>, map: Map<Int, Int>) {}\n                    |\n                    |class A(val map: Map<Int, Int>) {}\n                    |\n            \"\"\".trimMargin(),\n            DiktatError(5, 1, ruleId, \"${Warnings.USE_DATA_CLASS.warnText()} A\")\n        )\n    }\n\n    @Test\n    @Tag(USE_DATA_CLASS)\n    fun `should not trigger on empty class`() {\n        lintMethod(\n            \"\"\"\n                    |class B() {}\n                    |\n                    |class Ab{}\n                    |\n            \"\"\".trimMargin()\n        )\n    }\n\n    @Test\n    @Tag(USE_DATA_CLASS)\n    fun `should trigger on class without constructor but with property`() {\n        lintMethod(\n            \"\"\"\n                    |class B() {\n                    |   val q = 10\n                    |}\n                    |\n                    |class Ab {\n                    |   val qw = 10\n                    |}\n                    |\n                    |class Ba {\n                    |   val q = 10\n                    |   fun foo() = 10\n                    |}\n            \"\"\".trimMargin(),\n            DiktatError(1, 1, ruleId, \"${Warnings.USE_DATA_CLASS.warnText()} B\"),\n            DiktatError(5, 1, ruleId, \"${Warnings.USE_DATA_CLASS.warnText()} Ab\")\n        )\n    }\n\n    @Test\n    @Tag(USE_DATA_CLASS)\n    fun `shouldn't trigger on class with init block`() {\n        lintMethod(\n            \"\"\"\n                |class Credentials(auth: String) {\n                |   val gitHubUserName: String\n                |   val gitHubAuthToken: String\n                |\n                |   init {\n                |       auth.let {\n                |\n                |       }\n                |   }\n                |}\n            \"\"\".trimMargin()\n        )\n    }\n\n    @Test\n    @Tag(USE_DATA_CLASS)\n    fun `should not trigger on init block with if`() {\n        lintMethod(\n            \"\"\"\n                |class Credentials(auth: String, second: Int?, third: Double) {\n                |   val gitHubUserName: String\n                |   val gitHubAuthToken: String\n                |\n                |   init {\n                |       if (second != null) {\n                |       }\n                |   }\n                |}\n            \"\"\".trimMargin()\n        )\n    }\n\n    @Test\n    @Tag(USE_DATA_CLASS)\n    fun `should not trigger on init block with function call`() {\n        lintMethod(\n            \"\"\"\n                |class Credentials(auth: String, second: Int?, third: Double) {\n                |   val gitHubUserName: String\n                |   val gitHubAuthToken: String\n                |\n                |   init {\n                |       foo(third)\n                |   }\n                |}\n            \"\"\".trimMargin()\n        )\n    }\n\n    @Test\n    @Tag(USE_DATA_CLASS)\n    fun `should not trigger on class with several parameters`() {\n        lintMethod(\n            \"\"\"\n                |class Credentials(auth: String, second: Int?, third: Double) {\n                |   val gitHubUserName: String\n                |   val gitHubAuthToken: String\n                |\n                |   init {\n                |       auth.let {\n                |\n                |       }\n                |\n                |       if (second != null) {\n                |       }\n                |\n                |       foo(third)\n                |   }\n                |}\n            \"\"\".trimMargin()\n        )\n    }\n\n    @Test\n    @Tag(USE_DATA_CLASS)\n    fun `should not trigger on enums`() {\n        lintMethod(\n            \"\"\"\n                |enum class Style(val str: String) {\n                |    PASCAL_CASE(\"PascalCase\"),\n                |    SNAKE_CASE(\"UPPER_SNAKE_CASE\"),\n                |    ;\n                |}\n            \"\"\".trimMargin()\n        )\n    }\n\n    @Test\n    @Tag(USE_DATA_CLASS)\n    fun `should trigger on class with parameter in constructor`() {\n        lintMethod(\n            \"\"\"\n                |class Credentials(auth: String) {\n                |   val gitHubUserName: String = auth.toUpperCase()\n                |   val gitHubAuthToken: String = auth.toLowerCase()\n                |}\n            \"\"\".trimMargin(),\n            DiktatError(1, 1, ruleId, \"${Warnings.USE_DATA_CLASS.warnText()} Credentials\")\n        )\n    }\n\n    @Test\n    @Tag(USE_DATA_CLASS)\n    fun `should trigger on class with parameter in constructor and init block`() {\n        lintMethod(\n            \"\"\"\n                |class Credentials(auth: String) {\n                |   val gitHubUserName: String = auth.toUpperCase()\n                |   val gitHubAuthToken: String = auth.toLowerCase()\n                |\n                |   init {\n                |       // some logic\n                |   }\n                |}\n            \"\"\".trimMargin(),\n            DiktatError(1, 1, ruleId, \"${Warnings.USE_DATA_CLASS.warnText()} Credentials\")\n        )\n    }\n\n    @Test\n    @Tag(USE_DATA_CLASS)\n    fun `should not trigger on init block with one ref expression`() {\n        lintMethod(\n            \"\"\"\n                |class Credentials(auth: String, some: Int?) {\n                |   val gitHubUserName: String = auth.toUpperCase()\n                |   val gitHubAuthToken: String = auth.toLowerCase()\n                |\n                |   init {\n                |       val a = auth\n                |   }\n                |}\n            \"\"\".trimMargin()\n        )\n    }\n\n    @Test\n    @Tag(USE_DATA_CLASS)\n    fun `annotation classes bug`() {\n        lintMethod(\n            \"\"\"\n                |@Retention(AnnotationRetention.SOURCE)\n                |@Target(AnnotationTarget.CLASS)\n                |annotation class NavGraphDestination(\n                |    val name: String = Defaults.NULL,\n                |    val routePrefix: String = Defaults.NULL,\n                |    val deepLink: Boolean = false,\n                |) {\n                |    object Defaults {\n                |        const val NULL = \"@null\"\n                |    }\n                |}\n            \"\"\".trimMargin()\n        )\n    }\n\n    @Test\n    @Tag(USE_DATA_CLASS)\n    fun `value or inline classes bug`() {\n        lintMethod(\n            \"\"\"\n                |@JvmInline\n                |value class Password(private val s: String)\n                |val securePassword = Password(\"Don't try this in production\")\n            \"\"\".trimMargin()\n        )\n    }\n\n    @Test\n    @Tag(USE_DATA_CLASS)\n    fun `sealed classes bug`() {\n        lintMethod(\n            \"\"\"\n                |sealed class Password(private val s: String)\n            \"\"\".trimMargin()\n        )\n    }\n\n    @Test\n    @Tag(USE_DATA_CLASS)\n    fun `inner classes bug`() {\n        lintMethod(\n            \"\"\"\n                |inner class Password(private val s: String)\n            \"\"\".trimMargin()\n        )\n    }\n\n    @Test\n    @Tag(USE_DATA_CLASS)\n    fun `shouldn't trigger on interface`() {\n        lintMethod(\n            \"\"\"\n                |interface Credentials {\n                |   val code: String\n                |   val success: Boolean\n                |   val message: String\n                |}\n            \"\"\".trimMargin()\n        )\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/test/kotlin/com/saveourtool/diktat/ruleset/chapter6/EmptyPrimaryConstructorFixTest.kt",
    "content": "package com.saveourtool.diktat.ruleset.chapter6\n\nimport com.saveourtool.diktat.ruleset.rules.chapter6.AvoidEmptyPrimaryConstructor\nimport com.saveourtool.diktat.util.FixTestBase\n\nimport generated.WarningNames\nimport org.junit.jupiter.api.Tag\nimport org.junit.jupiter.api.Test\n\nclass EmptyPrimaryConstructorFixTest : FixTestBase(\"test/chapter6/primary_constructor\", ::AvoidEmptyPrimaryConstructor) {\n    @Test\n    @Tag(WarningNames.EMPTY_PRIMARY_CONSTRUCTOR)\n    fun `should remove empty primary constructor`() {\n        fixAndCompare(\"EmptyPCExpected.kt\", \"EmptyPCTest.kt\")\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/test/kotlin/com/saveourtool/diktat/ruleset/chapter6/EmptyPrimaryConstructorWarnTest.kt",
    "content": "package com.saveourtool.diktat.ruleset.chapter6\n\nimport com.saveourtool.diktat.common.config.rules.DIKTAT_RULE_SET_ID\nimport com.saveourtool.diktat.ruleset.constants.Warnings.EMPTY_PRIMARY_CONSTRUCTOR\nimport com.saveourtool.diktat.ruleset.rules.chapter6.AvoidEmptyPrimaryConstructor\nimport com.saveourtool.diktat.util.LintTestBase\n\nimport com.saveourtool.diktat.api.DiktatError\nimport generated.WarningNames\nimport org.junit.jupiter.api.Tag\nimport org.junit.jupiter.api.Test\n\nclass EmptyPrimaryConstructorWarnTest : LintTestBase(::AvoidEmptyPrimaryConstructor) {\n    private val ruleId = \"$DIKTAT_RULE_SET_ID:${AvoidEmptyPrimaryConstructor.NAME_ID}\"\n\n    @Test\n    @Tag(WarningNames.EMPTY_PRIMARY_CONSTRUCTOR)\n    fun `simple classes with empty primary constructor`() {\n        lintMethod(\n            \"\"\"\n                    |class Some() {\n                    |   val a = 10\n                    |   constructor(a: String): this() {\n                    |       this.a = a\n                    |   }\n                    |}\n                    |\n                    |class Some1() {\n                    |   val a = 10\n                    |   companion object {}\n                    |}\n                    |\n                    |class Some2 {\n                    |   val a = 10\n                    |   constructor(a: String): this() {\n                    |       this.a = a\n                    |   }\n                    |}\n                    |\n                    |class Some3 private constructor () {\n                    |\n                    |}\n            \"\"\".trimMargin(),\n            DiktatError(1, 1, ruleId, \"${EMPTY_PRIMARY_CONSTRUCTOR.warnText()} Some\", true),\n            DiktatError(8, 1, ruleId, \"${EMPTY_PRIMARY_CONSTRUCTOR.warnText()} Some1\", true)\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.EMPTY_PRIMARY_CONSTRUCTOR)\n    fun `correct example with empty primary constructor and modifiers`() {\n        lintMethod(\n            \"\"\"\n                    |class Some1 private constructor () {\n                    |\n                    |}\n                    |\n                    |class Some2 @Inject constructor() {\n                    |}\n            \"\"\".trimMargin()\n        )\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/test/kotlin/com/saveourtool/diktat/ruleset/chapter6/ExtensionFunctionsInFileWarnTest.kt",
    "content": "package com.saveourtool.diktat.ruleset.chapter6\n\nimport com.saveourtool.diktat.common.config.rules.DIKTAT_RULE_SET_ID\nimport com.saveourtool.diktat.ruleset.constants.Warnings\nimport com.saveourtool.diktat.ruleset.rules.chapter6.ExtensionFunctionsInFileRule\nimport com.saveourtool.diktat.util.LintTestBase\n\nimport com.saveourtool.diktat.api.DiktatError\nimport generated.WarningNames.EXTENSION_FUNCTION_WITH_CLASS\nimport org.junit.jupiter.api.Tag\nimport org.junit.jupiter.api.Test\n\nclass ExtensionFunctionsInFileWarnTest : LintTestBase(::ExtensionFunctionsInFileRule) {\n    private val ruleId = \"$DIKTAT_RULE_SET_ID:${ExtensionFunctionsInFileRule.NAME_ID}\"\n\n    @Test\n    @Tag(EXTENSION_FUNCTION_WITH_CLASS)\n    fun `should warn on function`() {\n        lintMethod(\n            \"\"\"\n                |class Some private constructor () {\n                |\n                |}\n                |\n                |private fun Some.coolStr() {\n                |\n                |}\n            \"\"\".trimMargin(),\n            DiktatError(5, 1, ruleId, \"${Warnings.EXTENSION_FUNCTION_WITH_CLASS.warnText()} fun coolStr\")\n        )\n    }\n\n    @Test\n    @Tag(EXTENSION_FUNCTION_WITH_CLASS)\n    fun `should warn on several functions`() {\n        lintMethod(\n            \"\"\"\n                |class Another private constructor () {\n                |\n                |}\n                |\n                |private fun /* Random comment */ Another.coolStr() {\n                |\n                |}\n                |\n                |private fun Another.extMethod() {\n                |\n                |}\n            \"\"\".trimMargin(),\n            DiktatError(5, 1, ruleId, \"${Warnings.EXTENSION_FUNCTION_WITH_CLASS.warnText()} fun coolStr\"),\n            DiktatError(9, 1, ruleId, \"${Warnings.EXTENSION_FUNCTION_WITH_CLASS.warnText()} fun extMethod\"),\n        )\n    }\n\n    @Test\n    @Tag(EXTENSION_FUNCTION_WITH_CLASS)\n    fun `should not raise a warning when there is no class`() {\n        lintMethod(\n            \"\"\"\n                |private fun String.coolStr() {\n                |\n                |}\n                |\n                |private fun /* Random comment */ Another.extMethod() {\n                |\n                |}\n            \"\"\".trimMargin()\n        )\n    }\n\n    @Test\n    @Tag(EXTENSION_FUNCTION_WITH_CLASS)\n    fun `should not raise a warning when there is no extension functions`() {\n        lintMethod(\n            \"\"\"\n                |class Some {\n                |\n                |}\n            \"\"\".trimMargin()\n        )\n    }\n\n    @Test\n    @Tag(EXTENSION_FUNCTION_WITH_CLASS)\n    fun `should not raise a warning when extension function is in the class`() {\n        lintMethod(\n            \"\"\"\n                |class Some {\n                |\n                |   fun Some.str() {\n                |\n                |   }\n                |}\n            \"\"\".trimMargin()\n        )\n    }\n\n    @Test\n    @Tag(EXTENSION_FUNCTION_WITH_CLASS)\n    fun `should not trigger on regular functions in the same file with class`() {\n        lintMethod(\n            \"\"\"\n                |class Some {\n                |   fun foo() {\n                |\n                |   }\n                |}\n                |\n                |fun bar() {\n                |\n                |}\n            \"\"\".trimMargin()\n        )\n    }\n\n    @Test\n    @Tag(EXTENSION_FUNCTION_WITH_CLASS)\n    fun `should not trigger on extension functions with different class`() {\n        lintMethod(\n            \"\"\"\n                |class Some {\n                |   fun foo() {\n                |\n                |   }\n                |}\n                |\n                |fun String.bar() {\n                |\n                |}\n            \"\"\".trimMargin()\n        )\n    }\n\n    /**\n     * See [#1586](https://github.com/saveourtool/diktat/issues/1586).\n     *\n     * @since 1.2.5\n     */\n    @Test\n    @Tag(EXTENSION_FUNCTION_WITH_CLASS)\n    fun `should raise no warnings for external interfaces`() {\n        lintMethod(\n            \"\"\"\n                |internal external interface External {\n                |    val a: Int\n                |}\n                |\n                |fun External.extension() = println(a)\n            \"\"\".trimMargin()\n        )\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/test/kotlin/com/saveourtool/diktat/ruleset/chapter6/ExtensionFunctionsSameNameWarnTest.kt",
    "content": "package com.saveourtool.diktat.ruleset.chapter6\n\nimport com.saveourtool.diktat.common.config.rules.DIKTAT_RULE_SET_ID\nimport com.saveourtool.diktat.ruleset.constants.Warnings\nimport com.saveourtool.diktat.ruleset.rules.chapter6.ExtensionFunctionsSameNameRule\nimport com.saveourtool.diktat.util.LintTestBase\n\nimport com.saveourtool.diktat.api.DiktatError\nimport generated.WarningNames.EXTENSION_FUNCTION_SAME_SIGNATURE\nimport org.junit.jupiter.api.Disabled\nimport org.junit.jupiter.api.Tag\nimport org.junit.jupiter.api.Test\n\nclass ExtensionFunctionsSameNameWarnTest : LintTestBase(::ExtensionFunctionsSameNameRule) {\n    private val ruleId = \"$DIKTAT_RULE_SET_ID:${ExtensionFunctionsSameNameRule.NAME_ID}\"\n\n    @Test\n    @Tag(EXTENSION_FUNCTION_SAME_SIGNATURE)\n    fun `should trigger on functions with same signatures`() {\n        lintMethod(\n            \"\"\"\n                |open class A\n                |class B: A(), C\n                |class D: A()\n                |\n                |fun A.foo() = \"A\"\n                |fun B.foo() = \"B\"\n                |fun D.foo() = \"D\"\n                |\n                |fun printClassName(s: A) { print(s.foo()) }\n                |\n                |fun main() { printClassName(B()) }\n            \"\"\".trimMargin(),\n            DiktatError(5, 1, ruleId, \"${Warnings.EXTENSION_FUNCTION_SAME_SIGNATURE.warnText()} fun A.foo[] and fun B.foo[]\"),\n            DiktatError(5, 1, ruleId, \"${Warnings.EXTENSION_FUNCTION_SAME_SIGNATURE.warnText()} fun A.foo[] and fun D.foo[]\"),\n            DiktatError(6, 1, ruleId, \"${Warnings.EXTENSION_FUNCTION_SAME_SIGNATURE.warnText()} fun A.foo[] and fun B.foo[]\"),\n            DiktatError(7, 1, ruleId, \"${Warnings.EXTENSION_FUNCTION_SAME_SIGNATURE.warnText()} fun A.foo[] and fun D.foo[]\"),\n        )\n    }\n\n    @Test\n    @Tag(EXTENSION_FUNCTION_SAME_SIGNATURE)\n    fun `should trigger on functions with same signatures 2`() {\n        lintMethod(\n            \"\"\"\n                |open class A\n                |class B: A(), C\n                |\n                |fun A.foo(some: Int) = \"A\"\n                |fun B.foo(some: Int) = \"B\"\n                |\n                |fun printClassName(s: A) { print(s.foo()) }\n                |\n                |fun main() { printClassName(B()) }\n            \"\"\".trimMargin(),\n            DiktatError(4, 1, ruleId, \"${Warnings.EXTENSION_FUNCTION_SAME_SIGNATURE.warnText()} fun A.foo[some] and fun B.foo[some]\"),\n            DiktatError(5, 1, ruleId, \"${Warnings.EXTENSION_FUNCTION_SAME_SIGNATURE.warnText()} fun A.foo[some] and fun B.foo[some]\")\n        )\n    }\n\n    @Test\n    @Tag(EXTENSION_FUNCTION_SAME_SIGNATURE)\n    fun `should not trigger on functions with different signatures`() {\n        lintMethod(\n            \"\"\"\n                |open class A\n                |class B: A(), C\n                |\n                |fun A.foo(): Boolean = return true\n                |fun B.foo() = \"B\"\n                |\n                |fun printClassName(s: A) { print(s.foo()) }\n                |\n                |fun main() { printClassName(B()) }\n            \"\"\".trimMargin()\n        )\n    }\n\n    @Test\n    @Tag(EXTENSION_FUNCTION_SAME_SIGNATURE)\n    fun `should not trigger on functions with different signatures 2`() {\n        lintMethod(\n            \"\"\"\n                |open class A\n                |class B: A(), C\n                |\n                |fun A.foo() = return true\n                |fun B.foo(some: Int) = \"B\"\n                |\n                |fun printClassName(s: A) { print(s.foo()) }\n                |\n                |fun main() { printClassName(B()) }\n            \"\"\".trimMargin()\n        )\n    }\n\n    @Test\n    @Tag(EXTENSION_FUNCTION_SAME_SIGNATURE)\n    fun `should not trigger on functions with unrelated classes`() {\n        lintMethod(\n            \"\"\"\n                |interface A\n                |class B: A\n                |class C\n                |\n                |fun C.foo() = \"C\"\n                |fun B.foo() = \"B\"\n                |\n                |fun printClassName(s: A) { print(s.foo()) }\n                |\n                |fun main() { printClassName(B()) }\n            \"\"\".trimMargin()\n        )\n    }\n\n    @Test\n    @Tag(EXTENSION_FUNCTION_SAME_SIGNATURE)\n    fun `should not trigger on regular func`() {\n        lintMethod(\n            \"\"\"\n                |interface A\n                |class B: A\n                |class C\n                |\n                |fun foo() = \"C\"\n                |fun bar() = \"B\"\n                |\n                |fun printClassName(s: A) { print(s.foo()) }\n                |\n                |fun main() { printClassName(B()) }\n            \"\"\".trimMargin()\n        )\n    }\n\n    @Test\n    @Disabled\n    @Tag(EXTENSION_FUNCTION_SAME_SIGNATURE)\n    fun `should trigger on classes in other files`() {\n        lintMethod(\n            \"\"\"\n                |fun A.foo() = \"A\"\n                |fun B.foo() = \"B\"\n                |\n                |fun printClassName(s: A) { print(s.foo()) }\n                |\n                |fun main() { printClassName(B()) }\n            \"\"\".trimMargin(),\n            DiktatError(1, 1, ruleId, \"${Warnings.EXTENSION_FUNCTION_SAME_SIGNATURE.warnText()} fun A.foo() and fun B.foo()\"),\n            DiktatError(2, 1, ruleId, \"${Warnings.EXTENSION_FUNCTION_SAME_SIGNATURE.warnText()} fun A.foo() and fun B.foo()\")\n        )\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/test/kotlin/com/saveourtool/diktat/ruleset/chapter6/ImplicitBackingPropertyWarnTest.kt",
    "content": "package com.saveourtool.diktat.ruleset.chapter6\n\nimport com.saveourtool.diktat.common.config.rules.DIKTAT_RULE_SET_ID\nimport com.saveourtool.diktat.ruleset.constants.Warnings\nimport com.saveourtool.diktat.ruleset.rules.chapter6.ImplicitBackingPropertyRule\nimport com.saveourtool.diktat.util.LintTestBase\n\nimport com.saveourtool.diktat.api.DiktatError\nimport generated.WarningNames.NO_CORRESPONDING_PROPERTY\nimport org.junit.jupiter.api.Tag\nimport org.junit.jupiter.api.Test\n\nclass ImplicitBackingPropertyWarnTest : LintTestBase(::ImplicitBackingPropertyRule) {\n    private val ruleId = \"$DIKTAT_RULE_SET_ID:${ImplicitBackingPropertyRule.NAME_ID}\"\n\n    @Test\n    @Tag(NO_CORRESPONDING_PROPERTY)\n    fun `not trigger on backing property`() {\n        lintMethod(\n            \"\"\"\n                    |class Some(val a: Int = 5) {\n                    |   private var _table: Map<String, Int>? = null\n                    |   val table:Map<String, Int>\n                    |       get() {\n                    |           if (_table == null) {\n                    |               _table = HashMap()\n                    |           }\n                    |           return _table ?: throw AssertionError(\"Set to null by another thread\")\n                    |       }\n                    |       set(value) { field = value }\n                    |}\n            \"\"\".trimMargin()\n        )\n    }\n\n    @Test\n    @Tag(NO_CORRESPONDING_PROPERTY)\n    fun `trigger on backing property`() {\n        lintMethod(\n            \"\"\"\n                    |class Some(val a: Int = 5) {\n                    |   private var a: Map<String, Int>? = null\n                    |   val table:Map<String, Int>\n                    |       get() {\n                    |           if (a == null) {\n                    |               a = HashMap()\n                    |           }\n                    |           return a ?: throw AssertionError(\"Set to null by another thread\")\n                    |       }\n                    |       set(value) { field = value }\n                    |}\n            \"\"\".trimMargin(),\n            DiktatError(3, 4, ruleId, \"${Warnings.NO_CORRESPONDING_PROPERTY.warnText()} table has no corresponding property with name _table\")\n        )\n    }\n\n    @Test\n    @Tag(NO_CORRESPONDING_PROPERTY)\n    fun `don't trigger on regular backing property`() {\n        lintMethod(\n            \"\"\"\n                    |class Some(val a: Int = 5) {\n                    |   private var _a: Map<String, Int>? = null\n                    |   private val _some:Int? = null\n                    |}\n            \"\"\".trimMargin()\n        )\n    }\n\n    @Test\n    @Tag(NO_CORRESPONDING_PROPERTY)\n    fun `don't trigger on regular property`() {\n        lintMethod(\n            \"\"\"\n                    |class Some(val a: Int = 5) {\n                    |   private var a: Map<String, Int>? = null\n                    |   private val some:Int? = null\n                    |   private val _prop: String? = null\n                    |}\n            \"\"\".trimMargin()\n        )\n    }\n\n    @Test\n    @Tag(NO_CORRESPONDING_PROPERTY)\n    fun `should not trigger if property has field in accessor`() {\n        lintMethod(\n            \"\"\"\n                    |class Some(val a: Int = 5) {\n                    |   val table:Map<String, Int>\n                    |       set(value) { field = value }\n                    |   val _table: Map<String,Int>? = null\n                    |\n                    |   val some: Int\n                    |       get() = 3\n                    |}\n            \"\"\".trimMargin()\n        )\n    }\n\n    @Test\n    @Tag(NO_CORRESPONDING_PROPERTY)\n    fun `should not trigger on property with constant return`() {\n        lintMethod(\n            \"\"\"\n                    |class Some(val a: Int = 5) {\n                    |   val table:Int\n                    |       get() {\n                    |           return 3\n                    |       }\n                    |       set(value) { field = value }\n                    |}\n            \"\"\".trimMargin()\n        )\n    }\n\n    @Test\n    @Tag(NO_CORRESPONDING_PROPERTY)\n    fun `should not trigger on property with chain call return`() {\n        lintMethod(\n            \"\"\"\n                    |class Some(val a: Int = 5) {\n                    |   val table:Int\n                    |       get() {\n                    |           val some = listOf(1,2,3)\n                    |           return some.filter { it -> it == 3}.first()\n                    |       }\n                    |       set(value) { field = value }\n                    |}\n            \"\"\".trimMargin()\n        )\n    }\n\n    @Test\n    @Tag(NO_CORRESPONDING_PROPERTY)\n    fun `should not trigger set accessor`() {\n        lintMethod(\n            \"\"\"\n                    |class Some(val a: Int = 5) {\n                    |   val foo\n                    |       set(value) {\n                    |           if(isDelegate) log.debug(value)\n                    |           field = value\n                    |       }\n                    |}\n            \"\"\".trimMargin()\n        )\n    }\n\n    @Test\n    @Tag(NO_CORRESPONDING_PROPERTY)\n    fun `should trigger set accessor`() {\n        lintMethod(\n            \"\"\"\n                    |class Some(val a: Int = 5) {\n                    |   val foo\n                    |       set(value) {\n                    |           if(isDelegate) log.debug(value)\n                    |           a = value\n                    |       }\n                    |}\n            \"\"\".trimMargin(),\n            DiktatError(2, 4, ruleId, \"${Warnings.NO_CORRESPONDING_PROPERTY.warnText()} foo has no corresponding property with name _foo\")\n        )\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/test/kotlin/com/saveourtool/diktat/ruleset/chapter6/InlineClassesWarnTest.kt",
    "content": "package com.saveourtool.diktat.ruleset.chapter6\n\nimport com.saveourtool.diktat.common.config.rules.DIKTAT_COMMON\nimport com.saveourtool.diktat.common.config.rules.DIKTAT_RULE_SET_ID\nimport com.saveourtool.diktat.common.config.rules.RulesConfig\nimport com.saveourtool.diktat.ruleset.constants.Warnings.INLINE_CLASS_CAN_BE_USED\nimport com.saveourtool.diktat.ruleset.rules.chapter6.classes.InlineClassesRule\nimport com.saveourtool.diktat.util.LintTestBase\n\nimport com.saveourtool.diktat.api.DiktatError\nimport generated.WarningNames\nimport org.junit.jupiter.api.Tag\nimport org.junit.jupiter.api.Test\n\nclass InlineClassesWarnTest : LintTestBase(::InlineClassesRule) {\n    private val ruleId = \"$DIKTAT_RULE_SET_ID:${InlineClassesRule.NAME_ID}\"\n    private val rulesConfigListEarlierVersion: List<RulesConfig> = listOf(\n        RulesConfig(\n            DIKTAT_COMMON, true,\n            mapOf(\"kotlinVersion\" to \"1.2.9\"))\n    )\n    private val rulesConfigListSameVersion: List<RulesConfig> = listOf(\n        RulesConfig(\n            DIKTAT_COMMON, true,\n            mapOf(\"kotlinVersion\" to \"1.3\"))\n    )\n    private val rulesConfigListLateVersion: List<RulesConfig> = listOf(\n        RulesConfig(\n            DIKTAT_COMMON, true,\n            mapOf(\"kotlinVersion\" to \"1.4.30\"))\n    )\n    private val rulesConfigListUnsupportedVersion: List<RulesConfig> = listOf(\n        RulesConfig(\n            DIKTAT_COMMON, true,\n            mapOf(\"kotlinVersion\" to \"1.5.20\"))\n    )\n\n    @Test\n    @Tag(WarningNames.INLINE_CLASS_CAN_BE_USED)\n    fun `should not trigger on inline class`() {\n        lintMethod(\n            \"\"\"\n                |inline class Name(val s: String) {}\n            \"\"\".trimMargin(),\n            rulesConfigList = rulesConfigListSameVersion\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.INLINE_CLASS_CAN_BE_USED)\n    fun `should trigger on regular class`() {\n        lintMethod(\n            \"\"\"\n                |class Some {\n                |   val config = Config()\n                |}\n            \"\"\".trimMargin(),\n            DiktatError(1, 1, ruleId, \"${INLINE_CLASS_CAN_BE_USED.warnText()} class Some\", false),\n            rulesConfigList = rulesConfigListSameVersion\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.INLINE_CLASS_CAN_BE_USED)\n    fun `should trigger on class with appropriate modifiers`() {\n        lintMethod(\n            \"\"\"\n                |final class Some {\n                |   val config = Config()\n                |}\n            \"\"\".trimMargin(),\n            DiktatError(1, 1, ruleId, \"${INLINE_CLASS_CAN_BE_USED.warnText()} class Some\", false),\n            rulesConfigList = rulesConfigListSameVersion\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.INLINE_CLASS_CAN_BE_USED)\n    fun `should not trigger on class with inappropriate modifiers`() {\n        lintMethod(\n            \"\"\"\n                |abstract class Some {\n                |   val config = Config()\n                |}\n            \"\"\".trimMargin(),\n            rulesConfigList = rulesConfigListSameVersion\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.INLINE_CLASS_CAN_BE_USED)\n    fun `should not trigger on interface`() {\n        lintMethod(\n            \"\"\"\n                |interface Some {\n                |   val config = Config()\n                |}\n            \"\"\".trimMargin(),\n            rulesConfigList = rulesConfigListSameVersion\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.INLINE_CLASS_CAN_BE_USED)\n    fun `should trigger on class with val prop in constructor`() {\n        lintMethod(\n            \"\"\"\n                |class Some(val anything: Int) {\n                |\n                |}\n            \"\"\".trimMargin(),\n            DiktatError(1, 1, ruleId, \"${INLINE_CLASS_CAN_BE_USED.warnText()} class Some\", false),\n            rulesConfigList = rulesConfigListSameVersion\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.INLINE_CLASS_CAN_BE_USED)\n    fun `should not trigger on class with var prop #1`() {\n        lintMethod(\n            \"\"\"\n                |class Some(var anything: Int) {\n                |\n                |}\n            \"\"\".trimMargin(),\n            rulesConfigList = rulesConfigListSameVersion\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.INLINE_CLASS_CAN_BE_USED)\n    fun `should not trigger on class with var prop #2`() {\n        lintMethod(\n            \"\"\"\n                |class Some {\n                |   var some = 3\n                |}\n            \"\"\".trimMargin(),\n            rulesConfigList = rulesConfigListSameVersion\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.INLINE_CLASS_CAN_BE_USED)\n    fun `should not trigger on class that extends class`() {\n        lintMethod(\n            \"\"\"\n                |class Some : Any() {\n                |   val some = 3\n                |}\n            \"\"\".trimMargin(),\n            rulesConfigList = rulesConfigListSameVersion\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.INLINE_CLASS_CAN_BE_USED)\n    fun `should trigger on class that extends interface`() {\n        lintMethod(\n            \"\"\"\n                |class Some : Any {\n                |   val some = 3\n                |}\n            \"\"\".trimMargin(),\n            DiktatError(1, 1, ruleId, \"${INLINE_CLASS_CAN_BE_USED.warnText()} class Some\", false),\n            rulesConfigList = rulesConfigListSameVersion\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.INLINE_CLASS_CAN_BE_USED)\n    fun `should not trigger on class with internal constructor`() {\n        lintMethod(\n            \"\"\"\n                |class LocalCommandExecutor internal constructor(private val command: String) {\n                |\n                |}\n            \"\"\".trimMargin(),\n            rulesConfigList = rulesConfigListSameVersion\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.INLINE_CLASS_CAN_BE_USED)\n    fun `should trigger on class with public constructor`() {\n        lintMethod(\n            \"\"\"\n                |class LocalCommandExecutor public constructor(private val command: String) {\n                |\n                |}\n            \"\"\".trimMargin(),\n            DiktatError(1, 1, ruleId, \"${INLINE_CLASS_CAN_BE_USED.warnText()} class LocalCommandExecutor\", false),\n            rulesConfigList = rulesConfigListSameVersion\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.INLINE_CLASS_CAN_BE_USED)\n    fun `should trigger on class with annotation before the constructor`() {\n        lintMethod(\n            \"\"\"\n                |class LocalCommandExecutor @Inject constructor(private val command: String) {\n                |\n                |}\n            \"\"\".trimMargin(),\n            DiktatError(1, 1, ruleId, \"${INLINE_CLASS_CAN_BE_USED.warnText()} class LocalCommandExecutor\", false),\n            rulesConfigList = rulesConfigListSameVersion\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.INLINE_CLASS_CAN_BE_USED)\n    @Suppress(\"TOO_LONG_FUNCTION\")\n    fun `check kotlin version`() {\n        lintMethod(\n            \"\"\"\n                |class Some {\n                |   val config = Config()\n                |}\n            \"\"\".trimMargin(),\n            DiktatError(1, 1, ruleId, \"${INLINE_CLASS_CAN_BE_USED.warnText()} class Some\", false),\n            rulesConfigList = rulesConfigListLateVersion\n        )\n\n        lintMethod(\n            \"\"\"\n                |class Some {\n                |   val config = Config()\n                |}\n            \"\"\".trimMargin(),\n            rulesConfigList = rulesConfigListEarlierVersion\n        )\n\n        lintMethod(\n            \"\"\"\n                |class Some {\n                |   val config = Config()\n                |}\n            \"\"\".trimMargin(),\n            DiktatError(1, 1, ruleId, \"${INLINE_CLASS_CAN_BE_USED.warnText()} class Some\", false),\n            rulesConfigList = rulesConfigListSameVersion\n        )\n\n        lintMethod(\n            \"\"\"\n                |class Some {\n                |   val config = Config()\n                |}\n            \"\"\".trimMargin(),\n            rulesConfigList = rulesConfigListUnsupportedVersion\n        )\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/test/kotlin/com/saveourtool/diktat/ruleset/chapter6/PropertyAccessorFieldsWarnTest.kt",
    "content": "package com.saveourtool.diktat.ruleset.chapter6\n\nimport com.saveourtool.diktat.common.config.rules.DIKTAT_RULE_SET_ID\nimport com.saveourtool.diktat.ruleset.constants.Warnings.WRONG_NAME_OF_VARIABLE_INSIDE_ACCESSOR\nimport com.saveourtool.diktat.ruleset.rules.chapter6.PropertyAccessorFields\nimport com.saveourtool.diktat.util.LintTestBase\n\nimport com.saveourtool.diktat.api.DiktatError\nimport generated.WarningNames\nimport org.junit.jupiter.api.Tag\nimport org.junit.jupiter.api.Test\n\nclass PropertyAccessorFieldsWarnTest : LintTestBase(::PropertyAccessorFields) {\n    private val ruleId = \"$DIKTAT_RULE_SET_ID:${PropertyAccessorFields.NAME_ID}\"\n\n    @Test\n    @Tag(WarningNames.WRONG_NAME_OF_VARIABLE_INSIDE_ACCESSOR)\n    fun `check simple correct examples`() {\n        lintMethod(\n            \"\"\"\n                    |class A {\n                    |\n                    |   var isEmpty: Boolean = false\n                    |   set(value) {\n                    |       println(\"Side effect\")\n                    |       field = value\n                    |   }\n                    |   get() = field\n                    |\n                    |   var isNotEmpty: Boolean = true\n                    |   set(value) {\n                    |       val q = isEmpty.and(true)\n                    |       field = value\n                    |   }\n                    |   get() {\n                    |       println(12345)\n                    |       return field\n                    |   }\n                    |}\n            \"\"\".trimMargin()\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.WRONG_NAME_OF_VARIABLE_INSIDE_ACCESSOR)\n    fun `check wrong setter and getter examples`() {\n        lintMethod(\n            \"\"\"\n                    |class A {\n                    |\n                    |   var isEmpty: Boolean = false\n                    |   set(values) {\n                    |       println(\"Side effect\")\n                    |       isEmpty = values\n                    |   }\n                    |\n                    |   var isNotEmpty: Boolean = true\n                    |   set(value) {\n                    |       val q = isNotEmpty.and(true)\n                    |       field = value\n                    |   }\n                    |   get() {\n                    |       println(12345)\n                    |       return isNotEmpty\n                    |   }\n                    |\n                    |   var isNotOk: Boolean = false\n                    |   set(values) {\n                    |       this.isNotOk = values\n                    |   }\n                    |}\n            \"\"\".trimMargin(),\n            DiktatError(4, 4, ruleId, \"${WRONG_NAME_OF_VARIABLE_INSIDE_ACCESSOR.warnText()} set(values) {...\"),\n            DiktatError(14, 4, ruleId, \"${WRONG_NAME_OF_VARIABLE_INSIDE_ACCESSOR.warnText()} get() {...\"),\n            DiktatError(20, 4, ruleId, \"${WRONG_NAME_OF_VARIABLE_INSIDE_ACCESSOR.warnText()} set(values) {...\")\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.WRONG_NAME_OF_VARIABLE_INSIDE_ACCESSOR)\n    @Suppress(\"TOO_LONG_FUNCTION\")\n    fun `check examples with local var`() {\n        lintMethod(\n            \"\"\"\n                    |class A {\n                    |\n                    |   var isEmpty: Boolean = false\n                    |   set(values) {\n                    |       fun foo() {\n                    |           val isEmpty = false\n                    |       }\n                    |       isEmpty = values\n                    |   }\n                    |\n                    |   var isNotOk: Boolean = false\n                    |   set(valuess) {\n                    |       var isNotOk = true\n                    |       isNotOk = valuess\n                    |   }\n                    |\n                    |   var isOk: Boolean = false\n                    |   set(valuess) {\n                    |       isOk = valuess\n                    |       var isOk = true\n                    |   }\n                    |\n                    |   var isNotEmpty: Boolean = true\n                    |   set(value) {\n                    |       val q = isNotEmpty\n                    |       field = value\n                    |   }\n                    |   get() = field\n                    |}\n            \"\"\".trimMargin(),\n            DiktatError(4, 4, ruleId, \"${WRONG_NAME_OF_VARIABLE_INSIDE_ACCESSOR.warnText()} set(values) {...\"),\n            DiktatError(18, 4, ruleId, \"${WRONG_NAME_OF_VARIABLE_INSIDE_ACCESSOR.warnText()} set(valuess) {...\"),\n            DiktatError(24, 4, ruleId, \"${WRONG_NAME_OF_VARIABLE_INSIDE_ACCESSOR.warnText()} set(value) {...\")\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.WRONG_NAME_OF_VARIABLE_INSIDE_ACCESSOR)\n    fun `shouldn't be triggered when there's a method with the same name as the property`() {\n        lintMethod(\n            \"\"\"\n                    |class A {\n                    |\n                    |   val blaBla: String\n                    |       get() = \"bla\".blaBla(\"bla\")\n                    |\n                    |   fun blaBla(string: String): String = this + string\n                    |\n                    |}\n            \"\"\".trimMargin()\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.WRONG_NAME_OF_VARIABLE_INSIDE_ACCESSOR)\n    fun `shouldn't be triggered when the property is an extension property`() {\n        lintMethod(\n            \"\"\"\n                    |class A {\n                    |\n                    |   fun String.foo() = 42\n                    |       val String.foo: Int\n                    |       get() = foo\n                    |\n                    |}\n            \"\"\".trimMargin()\n        )\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/test/kotlin/com/saveourtool/diktat/ruleset/chapter6/RunInScriptFixTest.kt",
    "content": "package com.saveourtool.diktat.ruleset.chapter6\n\nimport com.saveourtool.diktat.ruleset.rules.chapter6.RunInScript\nimport com.saveourtool.diktat.util.FixTestBase\n\nimport generated.WarningNames\nimport org.junit.jupiter.api.Tag\nimport org.junit.jupiter.api.Test\n\nclass RunInScriptFixTest : FixTestBase(\"test/chapter6/script\", ::RunInScript) {\n    @Test\n    @Tag(WarningNames.RUN_IN_SCRIPT)\n    fun `should wrap into run`() {\n        fixAndCompare(\"SimpleRunInScriptExpected.kts\", \"SimpleRunInScriptTest.kts\")\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/test/kotlin/com/saveourtool/diktat/ruleset/chapter6/RunInScriptWarnTest.kt",
    "content": "package com.saveourtool.diktat.ruleset.chapter6\n\nimport com.saveourtool.diktat.common.config.rules.DIKTAT_RULE_SET_ID\nimport com.saveourtool.diktat.ruleset.constants.Warnings.RUN_IN_SCRIPT\nimport com.saveourtool.diktat.ruleset.rules.chapter6.RunInScript\nimport com.saveourtool.diktat.util.LintTestBase\n\nimport com.saveourtool.diktat.api.DiktatError\nimport generated.WarningNames\nimport org.junit.jupiter.api.Tag\nimport org.junit.jupiter.api.Test\nimport org.junit.jupiter.api.io.TempDir\nimport java.nio.file.Path\n\nclass RunInScriptWarnTest : LintTestBase(::RunInScript) {\n    private val ruleId: String = \"$DIKTAT_RULE_SET_ID:${RunInScript.NAME_ID}\"\n\n    @Test\n    @Tag(WarningNames.RUN_IN_SCRIPT)\n    fun `check simple example`(@TempDir tempDir: Path) {\n        lintMethodWithFile(\n            \"\"\"\n                class A {}\n\n                fun foo() {\n                }\n\n                diktat {}\n\n                diktat({})\n\n                foo/*df*/()\n\n                foo( //dfdg\n                    10\n                )\n                println(\"hello\")\n\n                w.map { it -> it }\n\n                tasks.register(\"a\") {\n                    dependsOn(\"b\")\n                    doFirst {\n                        generateCodeStyle(file(\"rootDir/guide\"), file(\"rootDir/../wp\"))\n                    }\n                }\n\n            \"\"\".trimMargin(),\n            tempDir = tempDir,\n            fileName = \"src/main/kotlin/com/saveourtool/diktat/Example.kts\",\n            DiktatError(10, 17, ruleId, \"${RUN_IN_SCRIPT.warnText()} foo/*df*/()\", true),\n            DiktatError(12, 17, ruleId, \"${RUN_IN_SCRIPT.warnText()} foo( //dfdg...\", true),\n            DiktatError(15, 17, ruleId, \"${RUN_IN_SCRIPT.warnText()} println(\\\"hello\\\")\", true),\n            DiktatError(17, 17, ruleId, \"${RUN_IN_SCRIPT.warnText()} w.map { it -> it }\", true),\n            DiktatError(19, 17, ruleId, \"${RUN_IN_SCRIPT.warnText()} tasks.register(\\\"a\\\") {...\", true)\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.RUN_IN_SCRIPT)\n    fun `check correct examples`(@TempDir tempDir: Path) {\n        lintMethodWithFile(\n            \"\"\"\n                run {\n                    println(\"hello\")\n                }\n\n                run{println(\"hello\")}\n\n                val task = tasks.register(\"a\") {\n                }\n\n            \"\"\".trimMargin(),\n            tempDir = tempDir,\n            fileName = \"src/main/kotlin/com/saveourtool/diktat/Example.kts\"\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.RUN_IN_SCRIPT)\n    fun `check correct with custom wrapper`(@TempDir tempDir: Path) {\n        lintMethodWithFile(\n            \"\"\"\n                custom {\n                    println(\"hello\")\n                }\n\n                oneMore{println(\"hello\")}\n\n                another {\n                    println(\"hello\")\n                }\n            \"\"\".trimMargin(),\n            tempDir = tempDir,\n            fileName = \"src/main/kotlin/com/saveourtool/diktat/Example.kts\"\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.RUN_IN_SCRIPT)\n    fun `check gradle file`(@TempDir tempDir: Path) {\n        lintMethodWithFile(\n            \"\"\"\n                class A {}\n\n                fun foo() {\n                }\n\n                if(true) {\n                    goo()\n                }\n\n                diktat {}\n\n                diktat({})\n\n                foo/*df*/()\n\n                foo( //dfdg\n                    10\n                )\n                println(\"hello\")\n\n                w.map { it -> it }\n\n                (tasks.register(\"a\") {\n                    dependsOn(\"b\")\n                    doFirst {\n                        generateCodeStyle(file(\"rootDir/guide\"), file(\"rootDir/../wp\"))\n                    }\n                })\n\n            \"\"\".trimMargin(),\n            tempDir = tempDir,\n            fileName = \"src/main/kotlin/com/saveourtool/diktat/builds.gradle.kts\",\n            DiktatError(6, 17, ruleId, \"${RUN_IN_SCRIPT.warnText()} if(true) {...\", true)\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.RUN_IN_SCRIPT)\n    fun `check gradle script with eq expression`(@TempDir tempDir: Path) {\n        lintMethodWithFile(\n            \"\"\"\n                version = \"0.1.0-SNAPSHOT\"\n\n                diktat {}\n\n                diktat({})\n\n                foo/*df*/()\n\n                foo().goo()\n            \"\"\".trimMargin(),\n            tempDir = tempDir,\n            fileName = \"src/main/kotlin/com/saveourtool/diktat/builds.gradle.kts\"\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.RUN_IN_SCRIPT)\n    fun `check kts script with eq expression`(@TempDir tempDir: Path) {\n        lintMethodWithFile(\n            \"\"\"\n                version = \"0.1.0-SNAPSHOT\"\n\n                diktat {}\n\n                diktat({})\n\n                foo/*df*/()\n            \"\"\".trimMargin(),\n            tempDir = tempDir,\n            fileName = \"src/main/kotlin/com/saveourtool/diktat/Example.kts\",\n            DiktatError(1, 17, ruleId, \"${RUN_IN_SCRIPT.warnText()} version = \\\"0.1.0-SNAPSHOT\\\"\", true),\n            DiktatError(7, 17, ruleId, \"${RUN_IN_SCRIPT.warnText()} foo/*df*/()\", true)\n        )\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/test/kotlin/com/saveourtool/diktat/ruleset/chapter6/SingleConstructorRuleFixTest.kt",
    "content": "package com.saveourtool.diktat.ruleset.chapter6\n\nimport com.saveourtool.diktat.ruleset.rules.chapter6.classes.SingleConstructorRule\nimport com.saveourtool.diktat.util.FixTestBase\n\nimport generated.WarningNames\nimport org.junit.jupiter.api.Tag\nimport org.junit.jupiter.api.Test\n\nclass SingleConstructorRuleFixTest : FixTestBase(\"test/chapter6/classes\", ::SingleConstructorRule) {\n    @Test\n    @Tag(WarningNames.SINGLE_CONSTRUCTOR_SHOULD_BE_PRIMARY)\n    fun `should convert simple secondary constructor to primary`() {\n        fixAndCompare(\"SimpleConstructorExpected.kt\", \"SimpleConstructorTest.kt\")\n    }\n\n    @Test\n    @Tag(WarningNames.SINGLE_CONSTRUCTOR_SHOULD_BE_PRIMARY)\n    fun `should convert secondary constructor to a primary and init block`() {\n        fixAndCompare(\"ConstructorWithInitExpected.kt\", \"ConstructorWithInitTest.kt\")\n    }\n\n    @Test\n    @Tag(WarningNames.SINGLE_CONSTRUCTOR_SHOULD_BE_PRIMARY)\n    fun `should convert secondary constructor to a primary saving modifiers`() {\n        fixAndCompare(\"ConstructorWithModifiersExpected.kt\", \"ConstructorWithModifiersTest.kt\")\n    }\n\n    @Test\n    @Tag(WarningNames.SINGLE_CONSTRUCTOR_SHOULD_BE_PRIMARY)\n    fun `should keep custom assignments when converting secondary constructor`() {\n        fixAndCompare(\"ConstructorWithCustomAssignmentsExpected.kt\", \"ConstructorWithCustomAssignmentsTest.kt\")\n    }\n\n    @Test\n    @Tag(WarningNames.SINGLE_CONSTRUCTOR_SHOULD_BE_PRIMARY)\n    fun `should keep assignments and required local variables in an init block`() {\n        fixAndCompare(\"AssignmentWithLocalPropertyExpected.kt\", \"AssignmentWithLocalPropertyTest.kt\")\n    }\n\n    @Test\n    @Tag(WarningNames.SINGLE_CONSTRUCTOR_SHOULD_BE_PRIMARY)\n    fun `should not remove different comments`() {\n        fixAndCompare(\"ConstructorWithCommentsExpected.kt\", \"ConstructorWithCommentsTest.kt\")\n    }\n\n    @Test\n    @Tag(WarningNames.SINGLE_CONSTRUCTOR_SHOULD_BE_PRIMARY)\n    fun `should not replace constructor with init block`() {\n        fixAndCompare(\"ConstructorWithComplexAssignmentsExpected.kt\", \"ConstructorWithComplexAssignmentsTest.kt\")\n    }\n\n    @Test\n    @Tag(WarningNames.SINGLE_CONSTRUCTOR_SHOULD_BE_PRIMARY)\n    fun `should keep expression order`() {\n        fixAndCompare(\"ConstructorShouldKeepExpressionsOrderExpected.kt\", \"ConstructorShouldKeepExpressionsOrderTest.kt\")\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/test/kotlin/com/saveourtool/diktat/ruleset/chapter6/SingleConstructorRuleWarnTest.kt",
    "content": "package com.saveourtool.diktat.ruleset.chapter6\n\nimport com.saveourtool.diktat.common.config.rules.DIKTAT_RULE_SET_ID\nimport com.saveourtool.diktat.ruleset.constants.Warnings.SINGLE_CONSTRUCTOR_SHOULD_BE_PRIMARY\nimport com.saveourtool.diktat.ruleset.rules.chapter6.classes.SingleConstructorRule\nimport com.saveourtool.diktat.util.LintTestBase\n\nimport com.saveourtool.diktat.api.DiktatError\nimport generated.WarningNames\nimport org.junit.jupiter.api.Tag\nimport org.junit.jupiter.api.Test\n\nclass SingleConstructorRuleWarnTest : LintTestBase(::SingleConstructorRule) {\n    private val ruleId = \"$DIKTAT_RULE_SET_ID:${SingleConstructorRule.NAME_ID}\"\n\n    @Test\n    @Tag(WarningNames.SINGLE_CONSTRUCTOR_SHOULD_BE_PRIMARY)\n    fun `should suggest to convert single constructor to primary - positive example`() {\n        lintMethod(\n            \"\"\"\n                |class Test(var a: Int) { }\n                |\n                |class Test private constructor(var a: Int) { }\n            \"\"\".trimMargin()\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.SINGLE_CONSTRUCTOR_SHOULD_BE_PRIMARY)\n    fun `should suggest to convert single constructor to primary`() {\n        lintMethod(\n            \"\"\"\n                |class Test {\n                |    var a: Int\n                |\n                |    constructor(a: Int) {\n                |        this.a = a\n                |    }\n                |}\n            \"\"\".trimMargin(),\n            DiktatError(1, 1, ruleId, \"${SINGLE_CONSTRUCTOR_SHOULD_BE_PRIMARY.warnText()} in class <Test>\", true)\n        )\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/test/kotlin/com/saveourtool/diktat/ruleset/chapter6/SingleInitRuleFixTest.kt",
    "content": "package com.saveourtool.diktat.ruleset.chapter6\n\nimport com.saveourtool.diktat.ruleset.rules.chapter6.classes.SingleInitRule\nimport com.saveourtool.diktat.util.FixTestBase\n\nimport generated.WarningNames\nimport org.junit.jupiter.api.Tag\nimport org.junit.jupiter.api.Test\n\nclass SingleInitRuleFixTest : FixTestBase(\"test/chapter6/init_blocks\", ::SingleInitRule) {\n    @Test\n    @Tag(WarningNames.MULTIPLE_INIT_BLOCKS)\n    fun `should merge init blocks`() {\n        fixAndCompare(\"InitBlocksExpected.kt\", \"InitBlocksTest.kt\")\n    }\n\n    @Test\n    @Tag(WarningNames.MULTIPLE_INIT_BLOCKS)\n    fun `should move property assignments from init blocks to declarations`() {\n        fixAndCompare(\"InitBlockWithAssignmentsExpected.kt\", \"InitBlockWithAssignmentsTest.kt\")\n    }\n\n    @Test\n    @Tag(WarningNames.MULTIPLE_INIT_BLOCKS)\n    fun `should merge init blocks and move property assignments from init blocks to declarations`() {\n        fixAndCompare(\"InitBlocksWithAssignmentsExpected.kt\", \"InitBlocksWithAssignmentsTest.kt\")\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/test/kotlin/com/saveourtool/diktat/ruleset/chapter6/SingleInitRuleWarnTest.kt",
    "content": "package com.saveourtool.diktat.ruleset.chapter6\n\nimport com.saveourtool.diktat.common.config.rules.DIKTAT_RULE_SET_ID\nimport com.saveourtool.diktat.ruleset.constants.Warnings\nimport com.saveourtool.diktat.ruleset.rules.chapter6.classes.SingleInitRule\nimport com.saveourtool.diktat.util.LintTestBase\n\nimport com.saveourtool.diktat.api.DiktatError\nimport generated.WarningNames\nimport org.junit.jupiter.api.Tag\nimport org.junit.jupiter.api.Test\n\nclass SingleInitRuleWarnTest : LintTestBase(::SingleInitRule) {\n    private val ruleId = \"$DIKTAT_RULE_SET_ID:${SingleInitRule.NAME_ID}\"\n\n    @Test\n    @Tag(WarningNames.MULTIPLE_INIT_BLOCKS)\n    fun `should allow single init block`() {\n        lintMethod(\n            \"\"\"\n                |class Example {\n                |    init { println(\"Lorem ipsum\") }\n                |}\n            \"\"\".trimMargin()\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.MULTIPLE_INIT_BLOCKS)\n    fun `should forbid multiple init blocks`() {\n        lintMethod(\n            \"\"\"\n                |class Example {\n                |    init { println(\"Lorem ipsum\") }\n                |\n                |    val foo = 0\n                |\n                |    init { println(\"Dolor sit amet\") }\n                |}\n            \"\"\".trimMargin(),\n            DiktatError(1, 15, ruleId, \"${Warnings.MULTIPLE_INIT_BLOCKS.warnText()} in class <Example> found 2 `init` blocks\", true)\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.MULTIPLE_INIT_BLOCKS)\n    fun `should warn if properties are assigned in init block`() {\n        lintMethod(\n            \"\"\"\n                |class A(baseUrl: String, hardUrl: String) {\n                |    private val customUrl: String\n                |    init {\n                |        customUrl = \"${'$'}baseUrl/myUrl\"\n                |    }\n                |}\n            \"\"\".trimMargin(),\n            DiktatError(3, 5, ruleId, \"${Warnings.MULTIPLE_INIT_BLOCKS.warnText()} `init` block has assignments that can be moved to declarations\", true)\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.MULTIPLE_INIT_BLOCKS)\n    fun `shouldn't warn if property are assigned on property in init block`() {\n        lintMethod(\n            \"\"\"\n                |class A {\n                |    var a: String\n                |    var c: String\n                |\n                |    init {\n                |        val b: String = \"a\"\n                |        a = b\n                |\n                |        val d: String = \"c\"\n                |        c = foo(d)\n                |    }\n                |}\n            \"\"\".trimMargin()\n        )\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/test/kotlin/com/saveourtool/diktat/ruleset/chapter6/StatelessClassesRuleFixTest.kt",
    "content": "package com.saveourtool.diktat.ruleset.chapter6\n\nimport com.saveourtool.diktat.ruleset.rules.chapter6.classes.StatelessClassesRule\nimport com.saveourtool.diktat.util.FixTestBase\n\nimport generated.WarningNames.OBJECT_IS_PREFERRED\nimport org.junit.jupiter.api.Tag\nimport org.junit.jupiter.api.Test\n\nclass StatelessClassesRuleFixTest : FixTestBase(\"test/chapter6/stateless_classes\", ::StatelessClassesRule) {\n    @Test\n    @Tag(OBJECT_IS_PREFERRED)\n    fun `fix class to object keyword`() {\n        fixAndCompare(\"StatelessClassExpected.kt\", \"StatelessClassTest.kt\")\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/test/kotlin/com/saveourtool/diktat/ruleset/chapter6/StatelessClassesRuleWarnTest.kt",
    "content": "package com.saveourtool.diktat.ruleset.chapter6\n\nimport com.saveourtool.diktat.common.config.rules.DIKTAT_RULE_SET_ID\nimport com.saveourtool.diktat.ruleset.constants.Warnings\nimport com.saveourtool.diktat.ruleset.rules.chapter6.classes.StatelessClassesRule\nimport com.saveourtool.diktat.util.LintTestBase\n\nimport com.saveourtool.diktat.api.DiktatError\nimport generated.WarningNames.OBJECT_IS_PREFERRED\nimport org.junit.jupiter.api.Tag\nimport org.junit.jupiter.api.Test\n\nclass StatelessClassesRuleWarnTest : LintTestBase(::StatelessClassesRule) {\n    private val ruleId = \"$DIKTAT_RULE_SET_ID:${StatelessClassesRule.NAME_ID}\"\n\n    @Test\n    @Tag(OBJECT_IS_PREFERRED)\n    fun `should not trigger on class not extending any interface`() {\n        lintMethod(\n            \"\"\"\n                |class Some : I() {\n                |   override fun some()\n                |}\n            \"\"\".trimMargin()\n        )\n    }\n\n    @Test\n    @Tag(OBJECT_IS_PREFERRED)\n    fun `should trigger on class extending interface`() {\n        lintMethod(\n            \"\"\"\n                |class Some : I {\n                |   override fun some()\n                |}\n                |\n                |interface I {\n                |   fun some()\n                |}\n            \"\"\".trimMargin(),\n            DiktatError(1, 1, ruleId, \"${Warnings.OBJECT_IS_PREFERRED.warnText()} class Some\", true)\n        )\n    }\n\n    @Test\n    @Tag(OBJECT_IS_PREFERRED)\n    fun `should not trigger on class with constructor`() {\n        lintMethod(\n            \"\"\"\n                |class Some(b: Int) : I {\n                |\n                |   override fun some()\n                |}\n            \"\"\".trimMargin()\n        )\n    }\n\n    @Test\n    @Tag(OBJECT_IS_PREFERRED)\n    fun `should not trigger on class with no interface in this file`() {\n        lintMethod(\n            \"\"\"\n                |class Some : I {\n                |\n                |   override fun some()\n                |}\n            \"\"\".trimMargin()\n        )\n    }\n\n    @Test\n    @Tag(OBJECT_IS_PREFERRED)\n    fun `should not trigger on class with state`() {\n        lintMethod(\n            \"\"\"\n                |class Some : I {\n                |   val a = 5\n                |   override fun some()\n                |}\n            \"\"\".trimMargin()\n        )\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/test/kotlin/com/saveourtool/diktat/ruleset/chapter6/TrivialPropertyAccessorsFixTest.kt",
    "content": "package com.saveourtool.diktat.ruleset.chapter6\n\nimport com.saveourtool.diktat.ruleset.rules.chapter6.TrivialPropertyAccessors\nimport com.saveourtool.diktat.util.FixTestBase\n\nimport generated.WarningNames.TRIVIAL_ACCESSORS_ARE_NOT_RECOMMENDED\nimport org.junit.jupiter.api.Tag\nimport org.junit.jupiter.api.Test\n\nclass TrivialPropertyAccessorsFixTest : FixTestBase(\"test/chapter6/properties\", ::TrivialPropertyAccessors) {\n    @Test\n    @Tag(TRIVIAL_ACCESSORS_ARE_NOT_RECOMMENDED)\n    fun `fix trivial setters and getters`() {\n        fixAndCompare(\"TrivialPropertyAccessorsExpected.kt\", \"TrivialPropertyAccessorsTest.kt\")\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/test/kotlin/com/saveourtool/diktat/ruleset/chapter6/TrivialPropertyAccessorsWarnTest.kt",
    "content": "package com.saveourtool.diktat.ruleset.chapter6\n\nimport com.saveourtool.diktat.common.config.rules.DIKTAT_RULE_SET_ID\nimport com.saveourtool.diktat.ruleset.constants.Warnings\nimport com.saveourtool.diktat.ruleset.rules.chapter6.TrivialPropertyAccessors\nimport com.saveourtool.diktat.util.LintTestBase\n\nimport com.saveourtool.diktat.api.DiktatError\nimport generated.WarningNames.TRIVIAL_ACCESSORS_ARE_NOT_RECOMMENDED\nimport org.junit.jupiter.api.Tag\nimport org.junit.jupiter.api.Test\n\nclass TrivialPropertyAccessorsWarnTest : LintTestBase(::TrivialPropertyAccessors) {\n    private val ruleId = \"$DIKTAT_RULE_SET_ID:${TrivialPropertyAccessors.NAME_ID}\"\n\n    @Test\n    @Tag(TRIVIAL_ACCESSORS_ARE_NOT_RECOMMENDED)\n    fun `should trigger on trivial getter and setter`() {\n        lintMethod(\n            \"\"\"\n                    |class Test {\n                    |   val prop: Int = 0\n                    |       get() { return field }\n                    |       set(value) { field = value }\n                    |}\n            \"\"\".trimMargin(),\n            DiktatError(3, 8, ruleId, \"${Warnings.TRIVIAL_ACCESSORS_ARE_NOT_RECOMMENDED.warnText()} get() { return field }\", true),\n            DiktatError(4, 8, ruleId, \"${Warnings.TRIVIAL_ACCESSORS_ARE_NOT_RECOMMENDED.warnText()} set(value) { field = value }\", true)\n        )\n    }\n\n    @Test\n    @Tag(TRIVIAL_ACCESSORS_ARE_NOT_RECOMMENDED)\n    fun `should trigger on trivial getter and setter equal case`() {\n        lintMethod(\n            \"\"\"\n                    |class Test {\n                    |   val prop: Int = 0\n                    |       get() = field\n                    |}\n            \"\"\".trimMargin(),\n            DiktatError(3, 8, ruleId, \"${Warnings.TRIVIAL_ACCESSORS_ARE_NOT_RECOMMENDED.warnText()} get() = field\", true)\n        )\n    }\n\n    @Test\n    @Tag(TRIVIAL_ACCESSORS_ARE_NOT_RECOMMENDED)\n    fun `should not trigger on getter and setter`() {\n        lintMethod(\n            \"\"\"\n                    |class Test {\n                    |   val prop: Int = 0\n                    |       get() {\n                    |           val b = someLogic(field)\n                    |           return b\n                    |       }\n                    |       set(value) {\n                    |           val res = func(value)\n                    |           field = res\n                    |       }\n                    |}\n            \"\"\".trimMargin()\n        )\n    }\n\n    @Test\n    @Tag(TRIVIAL_ACCESSORS_ARE_NOT_RECOMMENDED)\n    fun `should not trigger on private setter`() {\n        lintMethod(\n            \"\"\"\n                    |class Test {\n                    |   var testName: String? = null\n                    |       private set\n                    |}\n            \"\"\".trimMargin()\n        )\n    }\n\n    @Test\n    @Tag(TRIVIAL_ACCESSORS_ARE_NOT_RECOMMENDED)\n    fun `should trigger on getter without braces`() {\n        lintMethod(\n            \"\"\"\n                    |class Test {\n                    |   val testName = 0\n                    |       get\n                    |}\n            \"\"\".trimMargin(),\n            DiktatError(3, 8, ruleId, \"${Warnings.TRIVIAL_ACCESSORS_ARE_NOT_RECOMMENDED.warnText()} get\", true)\n        )\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/test/kotlin/com/saveourtool/diktat/ruleset/chapter6/UseLastIndexFixTest.kt",
    "content": "package com.saveourtool.diktat.ruleset.chapter6\n\nimport com.saveourtool.diktat.ruleset.rules.chapter6.UseLastIndex\nimport com.saveourtool.diktat.util.FixTestBase\n\nimport org.junit.jupiter.api.Test\n\nclass UseLastIndexFixTest : FixTestBase(\"test/chapter6/lastIndex_change\", ::UseLastIndex) {\n    @Test\n    fun `fix example with white spaces`() {\n        fixAndCompare(\"UseAnyWhiteSpacesExpected.kt\", \"UseAnyWhiteSpacesTest.kt\")\n    }\n\n    @Test\n    fun `fix example with incorrect use length`() {\n        fixAndCompare(\"IncorrectUseLengthMinusOneExpected.kt\", \"IncorrectUseLengthMinusOneTest.kt\")\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/test/kotlin/com/saveourtool/diktat/ruleset/chapter6/UseLastIndexWarnTest.kt",
    "content": "package com.saveourtool.diktat.ruleset.chapter6\n\nimport com.saveourtool.diktat.common.config.rules.DIKTAT_RULE_SET_ID\nimport com.saveourtool.diktat.ruleset.constants.Warnings\nimport com.saveourtool.diktat.ruleset.rules.chapter6.UseLastIndex\nimport com.saveourtool.diktat.util.LintTestBase\n\nimport com.saveourtool.diktat.api.DiktatError\nimport generated.WarningNames\nimport org.junit.jupiter.api.Tag\nimport org.junit.jupiter.api.Test\n\nclass UseLastIndexWarnTest : LintTestBase(::UseLastIndex) {\n    private val ruleId = \"$DIKTAT_RULE_SET_ID:${UseLastIndex.NAME_ID}\"\n\n    @Test\n    @Tag(WarningNames.USE_LAST_INDEX)\n    fun `find method Length - 1 with many dot expressions`() {\n        lintMethod(\n            \"\"\"\n                    |val A = \"AAAAAAAA\"\n                    |val D = A.B.C.length - 1\n                    |\n            \"\"\".trimMargin(),\n            DiktatError(2, 9, ruleId, \"${Warnings.USE_LAST_INDEX.warnText()} A.B.C.length - 1\", true)\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.USE_LAST_INDEX)\n    fun `find method Length - 1 for mane line`() {\n        lintMethod(\n            \"\"\"\n                    |fun foo() {\n                    |   val A : String = \"AAAA\"\n                    |   var B = A.length\n                    |   -\n                    |   1\n                    |}\n            \"\"\".trimMargin()\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.USE_LAST_INDEX)\n    fun `find method Length - 1 with many spaces and tabulation`() {\n        lintMethod(\n            \"\"\"\n                    |val A : String = \"AAAA\"\n                    |var B =    A.length   -       1  + 214\n                    |var C = A.length - 19\n                    |\n            \"\"\".trimMargin(),\n            DiktatError(2, 12, ruleId, \"${Warnings.USE_LAST_INDEX.warnText() } A.length   -       1\", true)\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.USE_LAST_INDEX)\n    fun `find method Length - 1 without spaces`() {\n        lintMethod(\n            \"\"\"\n                    |val A : String = \"AAAA\"\n                    |var B = A.length-1\n                    |\n            \"\"\".trimMargin(),\n            DiktatError(2, 9, ruleId, \"${Warnings.USE_LAST_INDEX.warnText()} A.length-1\", true)\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.USE_LAST_INDEX)\n    fun `find method Length - 1 without length`() {\n        lintMethod(\n            \"\"\"\n                    |val A = \"AAAA\"\n                    |val B = -1\n                    |val C = 6 + 121\n                    |var D = B + C\n                    |var E = A.length + 1\n            \"\"\".trimMargin()\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.USE_LAST_INDEX)\n    fun `find method Length - 1 without -1`() {\n        lintMethod(\n            \"\"\"\n                    |val A = \"AAAA\"\n                    |val B = -1\n                    |val C = 6 + 4\n                    |val D = \"AAAA\".length - 1\n                    |\n                    |val M = \"ASDFG\".length\n                    |\n            \"\"\".trimMargin(),\n            DiktatError(4, 9, ruleId, \"${Warnings.USE_LAST_INDEX.warnText()} \\\"AAAA\\\".length - 1\", true)\n        )\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/test/kotlin/com/saveourtool/diktat/ruleset/chapter6/UselessSupertypeFixTest.kt",
    "content": "package com.saveourtool.diktat.ruleset.chapter6\n\nimport com.saveourtool.diktat.ruleset.rules.chapter6.UselessSupertype\nimport com.saveourtool.diktat.util.FixTestBase\n\nimport generated.WarningNames\nimport org.junit.jupiter.api.Tag\nimport org.junit.jupiter.api.Test\n\nclass UselessSupertypeFixTest : FixTestBase(\"test/paragraph6/useless-override\", ::UselessSupertype) {\n    @Test\n    @Tag(WarningNames.USELESS_SUPERTYPE)\n    fun `fix example with one super`() {\n        fixAndCompare(\"UselessOverrideExpected.kt\", \"UselessOverrideTest.kt\")\n    }\n\n    @Test\n    @Tag(WarningNames.USELESS_SUPERTYPE)\n    fun `fix several super`() {\n        fixAndCompare(\"SeveralSuperTypesExpected.kt\", \"SeveralSuperTypesTest.kt\")\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/test/kotlin/com/saveourtool/diktat/ruleset/chapter6/UselessSupertypeWarnTest.kt",
    "content": "package com.saveourtool.diktat.ruleset.chapter6\n\nimport com.saveourtool.diktat.common.config.rules.DIKTAT_RULE_SET_ID\nimport com.saveourtool.diktat.ruleset.constants.Warnings.USELESS_SUPERTYPE\nimport com.saveourtool.diktat.ruleset.rules.chapter6.UselessSupertype\nimport com.saveourtool.diktat.util.LintTestBase\n\nimport com.saveourtool.diktat.api.DiktatError\nimport generated.WarningNames\nimport org.junit.jupiter.api.Tag\nimport org.junit.jupiter.api.Test\n\nclass UselessSupertypeWarnTest : LintTestBase(::UselessSupertype) {\n    private val ruleId = \"$DIKTAT_RULE_SET_ID:${UselessSupertype.NAME_ID}\"\n\n    @Test\n    @Tag(WarningNames.USELESS_SUPERTYPE)\n    @Suppress(\"TOO_LONG_FUNCTION\")\n    fun `check simple wrong example`() {\n        lintMethod(\n            \"\"\"\n                    open class Rectangle {\n                        open fun draw() { /* ... */ }\n                    }\n\n                    class Square() : Rectangle() {\n                        override fun draw() {\n                        /**\n                         *\n                         * hehe\n                         */\n                            super<Rectangle>.draw()\n                        }\n                    }\n\n                    class Square2() : Rectangle() {\n                        override fun draw() {\n                            //hehe\n                            /*\n                                hehe\n                            */\n                            super<Rectangle>.draw()\n                        }\n                    }\n\n                    class Square2() : Rectangle() {\n                        override fun draw() {\n                            val q = super.draw()\n                        }\n                    }\n\n                    class A: Runnable {\n                        override fun run() {\n\n                        }\n                    }\n            \"\"\".trimMargin(),\n            DiktatError(11, 35, ruleId, \"${USELESS_SUPERTYPE.warnText()} Rectangle\", true),\n            DiktatError(21, 35, ruleId, \"${USELESS_SUPERTYPE.warnText()} Rectangle\", true)\n        )\n    }\n\n    @Test\n    @Tag(WarningNames.USELESS_SUPERTYPE)\n    fun `check example with two super`() {\n        lintMethod(\n            \"\"\"\n                    open class Rectangle {\n                        open fun draw() { /* ... */ }\n                    }\n\n                    interface KK {\n                        fun draw() {}\n                        fun kk() {}\n                    }\n\n                    class Square2() : Rectangle(), KK {\n                        override fun draw() {\n                            super<Rectangle>.draw()\n                            super<KK>.draw()\n                        }\n\n                        private fun goo() {\n                            super<KK>.kk()\n                        }\n\n                    }\n            \"\"\".trimMargin(),\n            DiktatError(17, 35, ruleId, \"${USELESS_SUPERTYPE.warnText()} KK\", true)\n        )\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/test/kotlin/com/saveourtool/diktat/ruleset/config/DiktatRuleConfigYamlReaderTest.kt",
    "content": "package com.saveourtool.diktat.ruleset.config\n\nimport com.saveourtool.diktat.common.config.rules.DIKTAT_COMMON\nimport com.saveourtool.diktat.common.config.rules.RulesConfig\nimport com.saveourtool.diktat.common.config.rules.getCommonConfiguration\nimport org.junit.jupiter.api.Test\nimport java.nio.file.Paths\nimport kotlin.io.path.inputStream\n\nclass DiktatRuleConfigYamlReaderTest {\n    @Test\n    fun `testing json reading`() {\n        val rulesConfigList: List<RulesConfig> = DiktatRuleConfigYamlReader()\n            .invoke(Paths.get(\"src/test/resources/test-rules-config.yml\").inputStream())\n        assert(rulesConfigList.any { it.name == \"CLASS_NAME_INCORRECT\" && it.enabled })\n        assert(rulesConfigList.find { it.name == \"CLASS_NAME_INCORRECT\" }?.configuration == emptyMap<String, String>())\n        assert(rulesConfigList.find { it.name == \"DIKTAT_COMMON\" }\n            ?.configuration?.get(\"domainName\") == \"com.saveourtool.diktat\")\n    }\n\n    @Test\n    fun `testing kotlin version`() {\n        val rulesConfigList: List<RulesConfig> = DiktatRuleConfigYamlReader()\n            .invoke(Paths.get(\"src/test/resources/test-rules-config.yml\").inputStream())\n        assert(rulesConfigList.getCommonConfiguration().kotlinVersion == kotlinVersion)\n        assert(rulesConfigList.getCommonConfiguration().testAnchors.contains(\"androidUnitTest\"))\n        assert(rulesConfigList.find { it.name == DIKTAT_COMMON }\n            ?.configuration\n            ?.get(\"kotlinVersion\")\n            ?.kotlinVersion() == kotlinVersion)\n    }\n\n    companion object {\n        private val kotlinVersion = KotlinVersion(1, 4, 21)\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/test/kotlin/com/saveourtool/diktat/ruleset/junit/BooleanOrDefault.kt",
    "content": "package com.saveourtool.diktat.ruleset.junit\n\n/**\n * @property valueOrNull a boolean value, or `null` (meaning the default value\n *   will be used).\n */\n@Suppress(\"WRONG_DECLARATIONS_ORDER\")\nenum class BooleanOrDefault(val valueOrNull: Boolean?) {\n    FALSE(false),\n    TRUE(true),\n    DEFAULT(null),\n    ;\n}\n"
  },
  {
    "path": "diktat-rules/src/test/kotlin/com/saveourtool/diktat/ruleset/junit/CloseablePath.kt",
    "content": "package com.saveourtool.diktat.ruleset.junit\n\nimport com.saveourtool.diktat.test.framework.util.resetPermissions\nimport com.saveourtool.diktat.test.framework.util.tryToDeleteOnExit\nimport org.junit.jupiter.api.extension.ExtensionContext.Store.CloseableResource\nimport java.io.IOException\nimport java.nio.file.DirectoryNotEmptyException\nimport java.nio.file.FileVisitResult\nimport java.nio.file.FileVisitResult.CONTINUE\nimport java.nio.file.Files.walkFileTree\nimport java.nio.file.NoSuchFileException\nimport java.nio.file.Path\nimport java.nio.file.SimpleFileVisitor\nimport java.nio.file.attribute.BasicFileAttributes\nimport java.util.SortedMap\nimport kotlin.io.path.absolute\nimport kotlin.io.path.deleteExisting\nimport kotlin.io.path.isDirectory\nimport kotlin.io.path.notExists\nimport kotlin.io.path.relativeToOrSelf\n\n/**\n * @property directory the temporary directory (will be recursively deleted once\n *   the test completes).\n */\ndata class CloseablePath(val directory: Path) : CloseableResource {\n    @Throws(IOException::class)\n    override fun close() {\n        val failures = deleteAllFilesAndDirectories()\n\n        if (failures.isNotEmpty()) {\n            throw failures.toIoException()\n        }\n    }\n\n    @Suppress(\"TOO_LONG_FUNCTION\")\n    @Throws(IOException::class)\n    private fun deleteAllFilesAndDirectories(): SortedMap<Path, IOException> {\n        if (directory.notExists()) {\n            return emptyMap<Path, IOException>().toSortedMap()\n        }\n\n        val failures: SortedMap<Path, IOException> = sortedMapOf()\n        directory.resetPermissions()\n        walkFileTree(directory, object : SimpleFileVisitor<Path>() {\n            override fun preVisitDirectory(dir: Path, attrs: BasicFileAttributes): FileVisitResult {\n                if (dir != directory) {\n                    dir.resetPermissions()\n                }\n                return CONTINUE\n            }\n\n            override fun visitFileFailed(file: Path, exc: IOException): FileVisitResult {\n                /*\n                 * `IOException` includes `AccessDeniedException` thrown by\n                 * non-readable or non-executable flags.\n                 */\n                resetPermissionsAndTryToDeleteAgain(file, exc)\n                return CONTINUE\n            }\n\n            override fun visitFile(file: Path, attributes: BasicFileAttributes): FileVisitResult =\n                file.deleteAndContinue()\n\n            override fun postVisitDirectory(dir: Path, exc: IOException?): FileVisitResult =\n                dir.deleteAndContinue()\n\n            private fun Path.deleteAndContinue(): FileVisitResult {\n                try {\n                    deleteExisting()\n                } catch (_: NoSuchFileException) {\n                    /*\n                     * Ignore.\n                     */\n                } catch (dnee: DirectoryNotEmptyException) {\n                    failures[this] = dnee\n                } catch (ioe: IOException) {\n                    /*\n                     * `IOException` includes `AccessDeniedException` thrown by\n                     * non-readable or non-executable flags.\n                     */\n                    resetPermissionsAndTryToDeleteAgain(this, ioe)\n                }\n                return CONTINUE\n            }\n\n            private fun resetPermissionsAndTryToDeleteAgain(path: Path, ioe: IOException) {\n                try {\n                    path.resetPermissions()\n                    if (path.isDirectory()) {\n                        walkFileTree(path, this)\n                    } else {\n                        path.deleteExisting()\n                    }\n                } catch (suppressed: Exception) {\n                    ioe.addSuppressed(suppressed)\n                    failures[path] = ioe\n                }\n            }\n        })\n        return failures\n    }\n\n    private fun SortedMap<Path, IOException>.toIoException(): IOException {\n        @Suppress(\"WRONG_NEWLINES\")  // False positives, see #1495.\n        val joinedPaths = keys\n            .asSequence()\n            .map(Path::tryToDeleteOnExit)\n            .map { path ->\n                path.relativeToOrSelf(directory)\n            }\n            .map(Any::toString)\n            .joinToString()\n\n        return IOException(\"Failed to delete temp directory ${directory.absolute()}. \" +\n                \"The following paths could not be deleted (see suppressed exceptions for details): $joinedPaths\").apply {\n            values.forEach(this::addSuppressed)\n        }\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/test/kotlin/com/saveourtool/diktat/ruleset/junit/ExpectedLintError.kt",
    "content": "package com.saveourtool.diktat.ruleset.junit\n\nimport com.saveourtool.diktat.api.DiktatError\n\n/**\n * The common super-interface for expected lint errors (extracted from the\n * annotated code).\n */\ninterface ExpectedLintError {\n    /**\n     * The line number (1-based).\n     */\n    val line: Int\n\n    /**\n     * The column number (1-based).\n     */\n    val column: Int\n\n    /**\n     * Converts this instance to a [DiktatError].\n     *\n     * @return the [DiktatError] which corresponds to this instance.\n     */\n    fun asLintError(): DiktatError\n}\n"
  },
  {
    "path": "diktat-rules/src/test/kotlin/com/saveourtool/diktat/ruleset/junit/ExpectedLintErrors.kt",
    "content": "package com.saveourtool.diktat.ruleset.junit\n\nimport com.saveourtool.diktat.ruleset.utils.leadingSpaceCount\nimport org.assertj.core.api.Assertions.assertThat\nimport org.intellij.lang.annotations.Language\n\n/**\n * @property code the filtered code w/o any annotation markers.\n * @property expectedErrors the list of expected lint errors.\n */\ndata class ExpectedLintErrors<out E : ExpectedLintError>(\n    @Language(\"kotlin\") val code: String,\n    val expectedErrors: List<E>,\n) {\n    init {\n        code.checkIndentTrimmed()\n    }\n\n    private companion object {\n        private fun String.checkIndentTrimmed() {\n            val commonIndent = lineSequence()\n                .filter(String::isNotEmpty)\n                .map(String::leadingSpaceCount)\n                .minOrNull() ?: return\n\n            assertThat(commonIndent)\n                .describedAs(\"The whole code fragment is indented with $commonIndent space(s). Did you forget to call `trimIndent()`?\")\n                .isZero\n        }\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/test/kotlin/com/saveourtool/diktat/ruleset/junit/NaturalDisplayName.kt",
    "content": "package com.saveourtool.diktat.ruleset.junit\n\nimport org.junit.jupiter.api.MethodOrderer.DisplayName\nimport org.junit.jupiter.api.MethodOrdererContext\n\n/**\n * Like [DisplayName], but uses the _natural sort_ order\n * (i. e. `test 9` < `test 10`).\n *\n * @see DisplayName\n */\nclass NaturalDisplayName : DisplayName() {\n    /**\n     * Sort the methods encapsulated in the supplied [MethodOrdererContext]\n     * alphanumerically based on their display names.\n     */\n    override fun orderMethods(context: MethodOrdererContext) =\n        context.methodDescriptors.sortWith { left, right ->\n            val leftDisplayName = left.displayName\n            val rightDisplayName = right.displayName\n\n            val leftArgs = callArguments.find(leftDisplayName)\n                ?.groups\n                ?.get(\"args\")\n                ?.value\n            val rightArgs = callArguments.find(rightDisplayName)\n                ?.groups\n                ?.get(\"args\")\n                ?.value\n\n            /*\n             * If two methods are invoked with the same arguments, exclude the\n             * arguments from the comparison, i. e. order `foo()` before `foobar()`.\n             */\n            val (leftName, rightName) = when {\n                leftArgs != null && leftArgs == rightArgs -> {\n                    val withoutArgs: String.() -> String = {\n                        substring(0, length - leftArgs.length - 2)\n                    }\n\n                    leftDisplayName.withoutArgs() to rightDisplayName.withoutArgs()\n                }\n\n                else -> leftDisplayName to rightDisplayName\n            }\n\n            naturalComparator(leftName)(rightName)\n        }\n\n    private companion object {\n        private val callArguments = Regex(\"\"\"\\((?<args>[^()]*)\\)$\"\"\")\n\n        /**\n         * For \"case 1\" and \"case 10\", returns \"case \" as the common prefix.\n         */\n        @Suppress(\"TYPE_ALIAS\")\n        private val commonNonNumericPrefix: (String) -> (String) -> String = { left ->\n            { right ->\n                left.commonPrefixWith(right).takeWhile(isNotDigit)\n            }\n        }\n\n        /**\n         * Returns `true` if this `Char` is not a digit, `false` otherwise.\n         */\n        private val isNotDigit: Char.() -> Boolean = {\n            !isDigit()\n        }\n\n        /**\n         * Parses this string as an [Int] number and returns the result. Returns\n         * `null` if the string is not a valid representation of a number.\n         */\n        private val asIntOrNull: String.() -> Int? = {\n            when {\n                isEmpty() -> null\n                else -> try {\n                    toInt()\n                } catch (_: NumberFormatException) {\n                    null\n                }\n            }\n        }\n\n        private fun naturalComparator(left: String): (String) -> Int = { right ->\n            val commonNonNumericPrefix = commonNonNumericPrefix(left)(right)\n\n            val numericInfix: String.() -> String = {\n                val tail = subSequence(commonNonNumericPrefix.length, length)\n\n                tail.takeWhile(Char::isDigit).toString()\n            }\n\n            val leftInfixRaw = left.numericInfix()\n            val rightInfixRaw = right.numericInfix()\n\n            val leftInfix = leftInfixRaw.asIntOrNull()\n            val rightInfix = rightInfixRaw.asIntOrNull()\n\n            when {\n                leftInfix != null && rightInfix != null -> when (leftInfix) {\n                    /*\n                     * When infixes are equal, recursively compare the\n                     * remainder suffixes. Thus, \"foo9Bar\" < \"foo9bar\".\n                     */\n                    rightInfix -> {\n                        val leftSuffix = left.substring(commonNonNumericPrefix.length + leftInfixRaw.length)\n                        val rightSuffix = right.substring(commonNonNumericPrefix.length + rightInfixRaw.length)\n                        naturalComparator(leftSuffix)(rightSuffix)\n                    }\n\n                    /*\n                     * \"foo9bar\" < \"foo10bar\".\n                     */\n                    else -> leftInfix - rightInfix\n                }\n\n                else -> left.compareTo(right)\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/test/kotlin/com/saveourtool/diktat/ruleset/junit/RuleInvocationContextProvider.kt",
    "content": "package com.saveourtool.diktat.ruleset.junit\n\nimport com.saveourtool.diktat.ruleset.utils.NEWLINE\nimport generated.WarningNames\nimport org.assertj.core.api.Assertions.assertThat\nimport org.intellij.lang.annotations.Language\nimport org.junit.jupiter.api.TestTemplate\nimport org.junit.jupiter.api.extension.ExtensionContext\nimport org.junit.jupiter.api.extension.TestTemplateInvocationContext\nimport org.junit.jupiter.api.extension.TestTemplateInvocationContextProvider\nimport org.junit.platform.commons.util.AnnotationUtils.isAnnotated\nimport java.util.stream.Stream\nimport kotlin.reflect.KClass\nimport kotlin.reflect.full.declaredMemberProperties\n\n/**\n * A common super-interface for rule-specific\n * [TestTemplateInvocationContextProvider] implementations.\n */\ninterface RuleInvocationContextProvider<A : Annotation, out E : ExpectedLintError> : TestTemplateInvocationContextProvider {\n    /**\n     * @return the [TestTemplate] annotation supported by this\n     *   [TestTemplateInvocationContextProvider] implementation.\n     */\n    fun annotationType(): KClass<A>\n\n    override fun supportsTestTemplate(context: ExtensionContext): Boolean =\n        isAnnotated(context.testMethod, annotationType().java)\n\n    /**\n     * @param context the extension context for the test template method about\n     *   to be invoked.\n     * @param supportedTags the list of check names that should be recognized\n     *   (implementation-dependent).\n     * @return a `Stream` of `TestTemplateInvocationContext` instances for the\n     *   invocation of the test template method.\n     */\n    fun provideTestTemplateInvocationContexts(context: ExtensionContext, supportedTags: List<String>): Stream<TestTemplateInvocationContext>\n\n    override fun provideTestTemplateInvocationContexts(context: ExtensionContext): Stream<TestTemplateInvocationContext> {\n        @Suppress(\"WRONG_NEWLINES\")  // False positives, see #1495.\n        val supportedTags = context\n            .tags\n            .asSequence()\n            .filter { tag ->\n                tag in warningNames\n            }.toList()\n\n        assertThat(supportedTags).describedAs(\"Please annotate `${annotationType().simpleName}` with `@Tag`\").isNotEmpty\n\n        return provideTestTemplateInvocationContexts(context, supportedTags)\n    }\n\n    /**\n     * Creates an (expected) lint error from the parsed annotation data.\n     *\n     * @param line the line of code which had the annotation (with the\n     *   annotation stripped).\n     * @param lineNumber the 1-based line number.\n     * @param tag the name of the check, one of [WarningNames].\n     * @param properties the properties of the lint error, if any (the map may\n     *   be empty).\n     * @return the lint error created.\n     */\n    fun expectedLintErrorFrom(\n        @Language(\"kotlin\") line: String,\n        lineNumber: Int,\n        tag: String,\n        properties: Map<String, String?>\n    ): E\n\n    /**\n     * Extracts list errors from the annotated code, using\n     * [expectedLintErrorFrom] as the factory method.\n     *\n     * @param code the annotated code.\n     * @param supportedTags the list of check names that should be recognized\n     *   (implementation-dependent).\n     * @param allowEmptyErrors whether the list of expected errors is allowed to\n     *   be empty (i.e. the code may contain no known annotations).\n     * @return the list of expected errors as well as the filtered code.\n     * @see expectedLintErrorFrom\n     */\n    @Suppress(\"TOO_LONG_FUNCTION\")\n    fun extractExpectedErrors(@Language(\"kotlin\") code: String,\n                              supportedTags: List<String>,\n                              allowEmptyErrors: Boolean\n    ): ExpectedLintErrors<E> {\n        require(supportedTags.isNotEmpty()) {\n            \"The list of supported tags is empty\"\n        }\n\n        val codeAnnotationRegex = codeAnnotationRegex(supportedTags)\n\n        val expectedErrors: MutableList<E> = mutableListOf()\n\n        @Suppress(\n            \"AVOID_NULL_CHECKS\",\n            \"WRONG_NEWLINES\")  // False positives, see #1495.\n        val filteredCode = code\n            .trimIndent()\n            .lineSequence()\n            .mapIndexed { index, line ->\n                extractExpectedError(index, line, codeAnnotationRegex)\n            }.map { (line, expectedError) ->\n                if (expectedError != null) {\n                    expectedErrors += expectedError\n                }\n\n                line\n            }.joinToString(separator = NEWLINE.toString())\n\n        assertThat(filteredCode)\n            .describedAs(\"The code is empty, please add some\")\n            .isNotEmpty\n        assertThat(filteredCode)\n            .describedAs(\"The code is blank, please add some non-whitespace\")\n            .isNotBlank\n        val supportedTagsDescription = when (supportedTags.size) {\n            1 -> supportedTags[0]\n            else -> \"any of $supportedTags\"\n        }\n        if (!allowEmptyErrors) {\n            assertThat(expectedErrors)\n                .describedAs(\"The code contains no expected-error annotations or an unsupported tag is used (should be $supportedTagsDescription). \" +\n                        \"Please annotate your code or set `includeWarnTests` to `false`:$NEWLINE$filteredCode\")\n                .isNotEmpty\n        }\n\n        return ExpectedLintErrors(filteredCode, expectedErrors)\n    }\n\n    @Suppress(\"NESTED_BLOCK\")\n    private fun extractExpectedError(\n        index: Int,\n        line: String,\n        codeAnnotationRegex: Regex\n    ): Pair<String, E?> =\n        when (val result = codeAnnotationRegex.matchEntire(line)) {\n            null -> line to null\n            else -> {\n                val groups = result.groups\n                val filteredLine = groups[CODE]?.value ?: line\n\n                val expectedError = when (val tag = groups[TAG]?.value) {\n                    null -> null\n                    else -> {\n                        val properties = when (val rawProperties = groups[PROPERTIES]?.value) {\n                            null -> emptyMap()\n                            else -> parseProperties(rawProperties)\n                        }\n\n                        expectedLintErrorFrom(\n                            line = filteredLine,\n                            lineNumber = index + 1,\n                            tag = tag,\n                            properties = properties)\n                    }\n                }\n\n                filteredLine to expectedError\n            }\n        }\n\n    private companion object {\n        private const val CODE = \"code\"\n\n        /**\n         * The common prefix code annotation comments will have.\n         */\n        private const val CODE_ANNOTATION_PREFIX = \"diktat\"\n\n        @Language(\"RegExp\")\n        private const val KEY = \"\"\"[^=,\\h]+\"\"\"\n        private const val KEY_GROUP = \"key\"\n        private const val PROPERTIES = \"properties\"\n        private const val TAG = \"tag\"\n\n        @Language(\"RegExp\")\n        private const val VALUE = \"\"\"[^,\\]]*?\"\"\"\n        private const val VALUE_GROUP = \"value\"\n        private val entryRegex = Regex(\"\"\"\\h*(?<$KEY_GROUP>$KEY)\\h*=\\h*(?<$VALUE_GROUP>$VALUE)\\h*\"\"\")\n\n        @Suppress(\n            \"WRONG_NEWLINES\",  // False positives, see #1495.\n            \"BLANK_LINE_BETWEEN_PROPERTIES\")  // False positives, see #1496.\n        private val warningNames = WarningNames::class\n            .declaredMemberProperties\n            .asSequence()\n            .map { property ->\n                property.name\n            }.toSet()\n\n        /**\n         * Matches single-line (trailing) comments which contain strings like\n         *\n         * ```\n         * diktat:CHECK_NAME\n         * ```\n         *\n         * or\n         *\n         * ```\n         * diktat:CHECK_NAME[name1 = value1, name2 = value2]\n         * ```\n         * Example:\n         *\n         * ```\n         * diktat:WRONG_INDENTATION[expectedIndent = 4]\n         * ```\n         */\n        private fun codeAnnotationRegex(supportedTags: List<String>): Regex {\n            require(supportedTags.isNotEmpty()) {\n                \"The list of supported tags is empty\"\n            }\n\n            val tagRegex = supportedTags.asSequence().map { tag ->\n                \"\"\"\\Q$tag\\E\"\"\"\n            }.joinToString(prefix = \"(?<$TAG>\", separator = \"|\", postfix = \")\")\n\n            return Regex(\"\"\"^(?<$CODE>.*?)\\h*//\\h*\\Q$CODE_ANNOTATION_PREFIX\\E:$tagRegex(?:\\[\\h*(?<$PROPERTIES>$KEY\\h*=\\h*$VALUE\\h*(?:,\\h*$KEY\\h*=\\h*$VALUE\\h*?)*)\\h*,?\\h*])?\\h*$\"\"\")\n        }\n\n        private fun parseProperties(rawProperties: String): Map<String, String?> =\n            rawProperties.splitToSequence(',').mapNotNull { entry ->\n                entryRegex.matchEntire(entry)?.let { result ->\n                    val groups = result.groups\n                    val key = groups[KEY_GROUP]?.value\n                    val value = groups[VALUE_GROUP]?.value\n\n                    when (key) {\n                        null -> null\n                        else -> key to value\n                    }\n                }\n            }.toMap()\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/test/kotlin/com/saveourtool/diktat/ruleset/smoke/RulesConfigValidationTest.kt",
    "content": "package com.saveourtool.diktat.ruleset.smoke\n\nimport com.saveourtool.diktat.ruleset.config.DiktatRuleConfigYamlReader\nimport com.saveourtool.diktat.ruleset.rules.DiktatRuleSetFactoryImpl\nimport com.saveourtool.diktat.test.framework.util.deleteIfExistsSilently\n\nimport com.charleskorn.kaml.InvalidPropertyValueException\nimport org.junit.jupiter.api.AfterEach\nimport org.junit.jupiter.api.Assertions\nimport org.junit.jupiter.api.BeforeEach\nimport org.junit.jupiter.api.Disabled\nimport org.junit.jupiter.api.Test\nimport org.junit.jupiter.api.assertThrows\n\nimport java.io.File\nimport java.lang.IllegalArgumentException\nimport kotlin.io.path.createTempFile\n\nclass RulesConfigValidationTest {\n    private lateinit var file: File\n\n    @BeforeEach\n    fun setUp() {\n        file = createTempFile().toFile()\n    }\n\n    @AfterEach\n    fun tearDown() {\n        file.toPath().deleteIfExistsSilently()\n    }\n\n    @Test\n    @Suppress(\"GENERIC_VARIABLE_WRONG_DECLARATION\")\n    fun `should throw error if name is missing in Warnings`() {\n        file.writeText(\n            \"\"\"\n                |- name: MISSING_DOC_TOP_LEVEL\n                |  enabled: true\n                |  configuration: {}\n            \"\"\".trimMargin()\n        )\n        val exception = assertThrows<IllegalArgumentException> {\n            diktatRuleSetFactory(diktatRuleConfigReader(file.inputStream()))\n        }\n        Assertions.assertEquals(\"Warning name <MISSING_DOC_TOP_LEVEL> in configuration file is invalid, did you mean <MISSING_KDOC_TOP_LEVEL>?\", exception.message)\n    }\n\n    @Test\n    fun `should throw error on invalid yml config`() {\n        file.writeText(\n            \"\"\"\n                |- name: PACKAGE_NAME_MISSING\n                |  enabled: true\n                |  configuration:\n            \"\"\".trimMargin()\n        )\n        assertThrows<InvalidPropertyValueException> {\n            diktatRuleSetFactory(diktatRuleConfigReader(file.inputStream()))\n        }\n    }\n\n    @Test\n    @Disabled(\"https://github.com/saveourtool/diKTat/issues/395\")\n    fun `should throw error on invalid configuration section`() {\n        file.writeText(\n            \"\"\"\n                |- name: TOO_LONG_FUNCTION\n                |  enabled: true\n                |  configuration:\n                |    maxFunctionLength: 1o\n                |    isIncludeHeader: Fslse\n            \"\"\".trimMargin()\n        )\n        diktatRuleSetFactory(diktatRuleConfigReader(file.inputStream()))\n    }\n\n    companion object {\n        private val diktatRuleSetFactory = DiktatRuleSetFactoryImpl()\n        private val diktatRuleConfigReader = DiktatRuleConfigYamlReader()\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/test/kotlin/com/saveourtool/diktat/ruleset/utils/AstNodeUtilsTest.kt",
    "content": "@file:Suppress(\n    \"HEADER_MISSING_IN_NON_SINGLE_CLASS_FILE\",\n    \"LOCAL_VARIABLE_EARLY_DECLARATION\",\n    \"AVOID_NULL_CHECKS\",\n)\n\npackage com.saveourtool.diktat.ruleset.utils\n\nimport com.saveourtool.diktat.api.DiktatErrorEmitter\nimport com.saveourtool.diktat.api.DiktatRule\nimport com.saveourtool.diktat.api.DiktatRuleSet\nimport com.saveourtool.diktat.ktlint.check\nimport com.saveourtool.diktat.util.applyToCode\n\nimport org.jetbrains.kotlin.KtNodeTypes\nimport org.jetbrains.kotlin.KtNodeTypes.CLASS\nimport org.jetbrains.kotlin.KtNodeTypes.CLASS_BODY\nimport org.jetbrains.kotlin.lexer.KtTokens.EOL_COMMENT\nimport org.jetbrains.kotlin.lexer.KtTokens.EQ\nimport org.jetbrains.kotlin.KtNodeTypes.FUN\nimport org.jetbrains.kotlin.lexer.KtTokens.IDENTIFIER\nimport org.jetbrains.kotlin.KtNodeTypes.INTEGER_CONSTANT\nimport org.jetbrains.kotlin.KtNodeTypes.MODIFIER_LIST\nimport org.jetbrains.kotlin.KtNodeTypes.PROPERTY\nimport org.jetbrains.kotlin.KtNodeTypes.TYPE_REFERENCE\nimport org.jetbrains.kotlin.KtNodeTypes.VALUE_PARAMETER_LIST\nimport org.jetbrains.kotlin.lexer.KtTokens.VAL_KEYWORD\nimport org.jetbrains.kotlin.lexer.KtTokens.WHITE_SPACE\nimport org.intellij.lang.annotations.Language\nimport org.jetbrains.kotlin.com.intellij.lang.ASTNode\nimport org.jetbrains.kotlin.com.intellij.psi.impl.source.tree.PsiWhiteSpaceImpl\nimport org.jetbrains.kotlin.com.intellij.psi.tree.IElementType\nimport org.jetbrains.kotlin.psi.stubs.elements.KtFileElementType\nimport org.jetbrains.kotlin.utils.addToStdlib.ifNotEmpty\nimport org.junit.jupiter.api.Assertions\nimport org.junit.jupiter.api.Test\n\n@Suppress(\"LargeClass\", \"UnsafeCallOnNullableType\")\nclass AstNodeUtilsTest {\n    @Test\n    @Suppress(\"TOO_LONG_FUNCTION\")\n    fun `String representation of ASTNode`() {\n        val code = \"\"\"\n            class Test {\n                val x = 0\n            }\n        \"\"\".trimIndent()\n        PrettyPrintingVisitor.assertStringRepr(KtFileElementType.INSTANCE, code, 0, 2, \"\"\"\n            |kotlin.FILE: \"class Test {\n            |    val x = 0\n            |}\"\n            |- PACKAGE_DIRECTIVE: \"\"\n            |- IMPORT_LIST: \"\"\n            |- CLASS: \"class Test {\n            |    val x = 0\n            |}\"\n            |-- class: \"class\"\n            |-- WHITE_SPACE: \" \"\n            |-- IDENTIFIER: \"Test\"\n            |-- WHITE_SPACE: \" \"\n            |-- CLASS_BODY: \"{\n            |    val x = 0\n            |}\"\n            |\n        \"\"\".trimMargin())\n\n        PrettyPrintingVisitor.assertStringRepr(KtFileElementType.INSTANCE, \"\"\"val x = 0\"\"\", expected = \"\"\"\n            |kotlin.FILE: \"val x = 0\"\n            |- PACKAGE_DIRECTIVE: \"\"\n            |- IMPORT_LIST: \"\"\n            |- PROPERTY: \"val x = 0\"\n            |-- val: \"val\"\n            |-- WHITE_SPACE: \" \"\n            |-- IDENTIFIER: \"x\"\n            |-- WHITE_SPACE: \" \"\n            |-- EQ: \"=\"\n            |-- WHITE_SPACE: \" \"\n            |-- INTEGER_CONSTANT: \"0\"\n            |--- INTEGER_LITERAL: \"0\"\n            |\n        \"\"\".trimMargin())\n    }\n\n    @Test\n    fun `test node's check text length`() {\n        val code = \"\"\"\n            class Test {\n                /**\n                * test method\n                * @param a - dummy int\n                */\n                fun foo(a: Int): Int = 2 * a\n            }\n        \"\"\".trimIndent()\n        applyToCode(code, 1) { node, counter ->\n            if (node.elementType == CLASS) {\n                Assertions.assertTrue(node.isTextLengthInRange(IntRange(code.length, code.length)))\n                counter.incrementAndGet()\n            }\n        }\n    }\n\n    @Test\n    fun `test IdentifierName`() {\n        val code = \"\"\"\n            class Test {\n                /**\n                * test method\n                * @param a - dummy int\n                */\n                fun foo(a: Int): Int = 2 * a\n            }\n        \"\"\".trimIndent()\n        val list = listOf(\"Test\", \"foo\", \"a\", \"a\", \"Int\", \"Int\", \"a\")\n        applyToCode(code, 7) { node, counter ->\n            node.getIdentifierName()?.let {\n                Assertions.assertEquals(list[counter.get()], it.text)\n                counter.incrementAndGet()\n            }\n        }\n    }\n\n    @Test\n    fun `test getTypeParameterList`() {\n        val code = \"\"\"\n            class Array<T>(val size: Int) {\n\n            }\n        \"\"\".trimIndent()\n        applyToCode(code, 1) { node, counter ->\n            if (node.getTypeParameterList() != null) {\n                Assertions.assertEquals(\"<T>\", node.getTypeParameterList()!!.text)\n                counter.incrementAndGet()\n            }\n        }\n    }\n\n    @Test\n    fun `test getAllIdentifierChildren`() {\n        val code = \"\"\"\n            class Test() {\n                /**\n                * test method\n                * @param a - dummy int\n                */\n                fun foo(a: Int): Int = 2 * a\n            }\n        \"\"\".trimIndent()\n        val list = listOf(\"Test\", \"foo\", \"a\", \"a\", \"Int\", \"Int\", \"a\")\n        applyToCode(code, 7) { node, counter ->\n            node.getAllChildrenWithType(IDENTIFIER).ifNotEmpty {\n                this.forEach { Assertions.assertEquals(list[counter.get()], it.text) }\n                counter.incrementAndGet()\n            }\n        }\n    }\n\n    @Test\n    fun `test getAllChildrenWithType`() {\n        val code = \"\"\"\n            class Test() {\n                /**\n                * test method\n                * @param a - dummy int\n                */\n                fun foo(a: Int): Int = 2 * a\n            }\n        \"\"\".trimIndent()\n        applyToCode(code, 2) { node, counter ->\n            node.getAllChildrenWithType(CLASS).ifNotEmpty {\n                Assertions.assertEquals(map { it.text }, listOf(code))\n                counter.incrementAndGet()\n            }\n            if (node.getAllChildrenWithType(IDENTIFIER).isNotEmpty() && node.treeParent.elementType == KtFileElementType.INSTANCE) {\n                Assertions.assertEquals(node.getAllChildrenWithType(IDENTIFIER)[0].text, \"Test\")\n                counter.incrementAndGet()\n            }\n        }\n    }\n\n    @Test\n    fun `test getFirstChildWithType`() {\n        val code = \"\"\"\n            class Test() {\n                /**\n                * test method\n                * @param a - dummy int\n                */\n                fun foo(a: Int): Int = 2 * a\n            }\n        \"\"\".trimIndent()\n        applyToCode(code, 1) { node, counter ->\n            if (node.getAllChildrenWithType(IDENTIFIER).isNotEmpty() && node.treeParent.elementType == KtFileElementType.INSTANCE) {\n                Assertions.assertEquals(node.getFirstChildWithType(IDENTIFIER)!!.text, \"Test\")\n                counter.incrementAndGet()\n            }\n        }\n    }\n\n    @Test\n    fun `test hasChildOfType`() {\n        val code = \"\"\"\n            class Test {\n                val x = 0\n            }\n        \"\"\".trimIndent()\n        applyToCode(code, 2) { node, counter ->\n            if (node.getIdentifierName() != null) {\n                Assertions.assertTrue(node.hasChildOfType(IDENTIFIER))\n                counter.incrementAndGet()\n            }\n        }\n    }\n\n    @Test\n    fun `test hasAnyChildOfTypes`() {\n        val code = \"\"\"\n            class Test {\n                val x = 0\n            }\n        \"\"\".trimIndent()\n        applyToCode(code, 3) { node, counter ->\n            if (node.getAllChildrenWithType(IDENTIFIER).isNotEmpty() || node.getAllChildrenWithType(CLASS).isNotEmpty()) {\n                Assertions.assertTrue(node.hasAnyChildOfTypes(IDENTIFIER, CLASS))\n                counter.incrementAndGet()\n            }\n        }\n    }\n\n    @Test\n    fun `test findChildBefore`() {\n        val code = \"\"\"\n            class Test() {\n                /**\n                * test method\n                * @param a - dummy int\n                */\n                fun foo(a: Int): Int = 2 * a\n            }\n        \"\"\".trimIndent()\n        applyToCode(code, 1) { node, counter ->\n            if (node.findChildBefore(CLASS_BODY, CLASS) != null) {\n                Assertions.assertEquals(node.findChildBefore(CLASS_BODY, CLASS)!!.text, code)\n                counter.incrementAndGet()\n            }\n        }\n    }\n\n    @Test\n    fun `test findChildBefore - with siblings`() {\n        val code = \"\"\"\n            class Test() {\n                /**\n                * test method\n                * @param a - dummy int\n                */\n                fun foo(a: Int): Int = 2 * a\n            }\n        \"\"\".trimIndent()\n        val list = listOf(\"Test\", \"foo\", \"a\", \"a\", \"Int\", \"Int\", \"a\")\n        applyToCode(code, 7) { node, counter ->\n            if (node.findChildBefore(CLASS_BODY, IDENTIFIER) != null) {\n                Assertions.assertEquals(node.findChildBefore(CLASS_BODY, IDENTIFIER)!!.text, list[counter.get()])\n                counter.incrementAndGet()\n            }\n        }\n    }\n\n    @Test\n    fun `test findChildAfter`() {\n        val code = \"\"\"\n            class Test() {\n                /**\n                * test method\n                * @param a - dummy int\n                */\n                fun foo(a: Int): Int = 2 * a\n            }\n        \"\"\".trimIndent()\n        applyToCode(code, 1) { node, counter ->\n            node.findChildAfter(VALUE_PARAMETER_LIST, TYPE_REFERENCE)?.let {\n                Assertions.assertEquals(\"Int\", it.text)\n                counter.incrementAndGet()\n            }\n        }\n    }\n\n    @Test\n    fun `test allSiblings withSelf - true`() {\n        val code = \"\"\"\n            class Test() {\n                /**\n                * test method\n                * @param a - dummy int\n                */\n                fun foo(a: Int): Int = 2 * a\n            }\n        \"\"\".trimIndent()\n        applyToCode(code, 0) { node, _ ->\n            val setParent = if (node.treeParent != null) {\n                node.treeParent.getChildren(null).toSet()\n            } else {\n                setOf(node)\n            }\n            val setSibling = node.allSiblings(true).toSet()\n            Assertions.assertEquals(setParent, setSibling)\n            Assertions.assertTrue(setParent.isNotEmpty())\n        }\n    }\n\n    @Test\n    fun `regression - check for companion object`() {\n        applyToCode(\"\"\"\n                object Test {\n                    val id = 1\n            \t}\n            \"\"\".trimIndent(), 1) { node, counter ->\n            if (node.elementType == PROPERTY) {\n                Assertions.assertFalse(node.isNodeFromCompanionObject())\n                counter.incrementAndGet()\n            }\n        }\n\n        applyToCode(\"\"\"\n                companion object Test {\n                    val id = 1\n            \t}\n            \"\"\".trimIndent(), 1) { node, counter ->\n            if (node.elementType == PROPERTY) {\n                Assertions.assertTrue(node.isNodeFromCompanionObject())\n                counter.incrementAndGet()\n            }\n        }\n    }\n\n    @Test\n    fun `test isNodeFromCompanionObject`() {\n        val positiveExample = \"\"\"\n            class Something{\n            \tcompanion object {\n                    val id = 1\n            \t}\n            }\n        \"\"\".trimIndent()\n        applyToCode(positiveExample, 1) { node, counter ->\n            if (node.elementType == PROPERTY) {\n                Assertions.assertTrue(node.isNodeFromCompanionObject())\n                counter.incrementAndGet()\n            }\n        }\n        val negativeExample = \"\"\"\n            class Test() {\n                /**\n                * test method\n                * @param a - dummy int\n                */\n                fun foo(a: Int): Int = 2 * a\n            }\n        \"\"\".trimIndent()\n        applyToCode(negativeExample, 1) { node, counter ->\n            if (node.elementType == FUN) {\n                Assertions.assertFalse(node.isNodeFromCompanionObject())\n                counter.incrementAndGet()\n            }\n        }\n    }\n\n    @Test\n    fun `test node is from object `() {\n        val code = \"\"\"\n            object Something{\n                    val id = 1\n            }\n        \"\"\".trimIndent()\n        applyToCode(code, 1) { node, counter ->\n            if (node.elementType == PROPERTY) {\n                Assertions.assertTrue(node.isNodeFromObject())\n                counter.incrementAndGet()\n            }\n        }\n    }\n\n    @Test\n    fun `test isNodeFromFileLevel - node from file level`() {\n        val code = \"\"\"\n            class Test() {\n                /**\n                * test method\n                * @param a - dummy int\n                */\n                fun foo(a: Int): Int = 2 * a\n            }\n        \"\"\".trimIndent()\n        applyToCode(code, 1) { node, counter ->\n            if (node.treeParent != null && node.elementType == CLASS) {\n                Assertions.assertTrue(node.isNodeFromFileLevel())\n                counter.incrementAndGet()\n            }\n        }\n    }\n\n    @Test\n    fun `test isNodeFromFileLevel - node isn't from file level`() {\n        val code = \"\"\"\n            val x = 2\n\n        \"\"\".trimIndent()\n        applyToCode(code, 8) { node, counter ->\n            if (node.elementType != KtFileElementType.INSTANCE) {\n                node.getChildren(null).forEach {\n                    Assertions.assertFalse(it.isNodeFromFileLevel())\n                    counter.incrementAndGet()\n                }\n            }\n        }\n    }\n\n    @Test\n    fun `test isValProperty`() {\n        val code = \"\"\"\n            class Test() {\n\n                private val name = \"John\"\n\n                /**\n                * test method\n                * @param a - dummy int\n                */\n                fun foo(a: Int): Int = 2 * a\n            }\n        \"\"\".trimIndent()\n        var isVal = false\n        applyToCode(code, 0) { node, _ ->\n            if (node.isValProperty()) {\n                isVal = true\n            }\n        }\n        Assertions.assertTrue(isVal)\n    }\n\n    @Test\n    fun `test isConst`() {\n        val code = \"\"\"\n            class Test() {\n\n                const val SPEED = 10\n\n                /**\n                * test method\n                * @param a - dummy int\n                */\n                fun foo(a: Int): Int = 2 * a\n            }\n        \"\"\".trimIndent()\n        var isConst = false\n        applyToCode(code, 0) { node, _ ->\n            if (node.isConst()) {\n                isConst = true\n            }\n        }\n        Assertions.assertTrue(isConst)\n    }\n\n    @Test\n    fun `test isVarProperty`() {\n        val code = \"\"\"\n            class Test() {\n\n                private var name: String? = null\n\n                /**\n                * test method\n                * @param a - dummy int\n                */\n                fun foo(a: Int): Int = 2 * a\n            }\n        \"\"\".trimIndent()\n        var isVar = false\n        applyToCode(code, 0) { node, _ ->\n            if (node.isVarProperty()) {\n                isVar = true\n            }\n        }\n        Assertions.assertTrue(isVar)\n    }\n\n    @Test\n    fun `test getAllLLeafsWithSpecificType`() {\n        val code = \"\"\"\n            class Test() {\n                /**\n                * test method\n                * @param a - dummy int\n                */\n                fun foo(a: Int): Int = 2 * a\n            }\n        \"\"\".trimIndent()\n        val list: MutableList<ASTNode> = mutableListOf()\n        val leafWithTypeList: MutableList<ASTNode> = mutableListOf()\n        var firstNode: ASTNode? = null\n        applyToCode(code, 0) { node, _ ->\n            if (firstNode == null) {\n                firstNode = node\n            }\n            if (node.isLeaf() && node.elementType == WHITE_SPACE) {\n                leafWithTypeList.add(node)\n            }\n        }\n        firstNode?.getAllLeafsWithSpecificType(WHITE_SPACE, list)\n        Assertions.assertEquals(list, leafWithTypeList)\n    }\n\n    @Test\n    @Suppress(\"UnsafeCallOnNullableType\")\n    fun `test findLeafWithSpecificType`() {\n        val code = \"\"\"\n            class Test() {\n                /**\n                * test method\n                * @param a - dummy int\n                */\n                fun foo(a: Int): Int = 2 * a\n            }\n        \"\"\".trimIndent()\n        var firstNode: ASTNode? = null\n        var resultNode: ASTNode? = null\n        applyToCode(code, 0) { node, _ ->\n            if (firstNode == null) {\n                firstNode = node\n            }\n            if (resultNode == null && node.elementType == CLASS_BODY) {\n                resultNode = node\n            }\n        }\n        firstNode = firstNode?.findLeafWithSpecificType(CLASS_BODY)\n        Assertions.assertEquals(resultNode!!.text, firstNode!!.text)\n    }\n\n    @Test\n    fun `test findAllNodesWithSpecificType`() {\n        val code = \"\"\"\n            class Test() {\n                /**\n                * test method\n                * @param a - dummy int\n                */\n                fun foo(a: Int): Int = 2 * a\n            }\n        \"\"\".trimIndent()\n        var firstNode: ASTNode? = null\n        val listResults: MutableList<ASTNode> = mutableListOf()\n        applyToCode(code, 0) { node, _ ->\n            if (firstNode == null) {\n                firstNode = node\n            }\n            if (node.elementType == IDENTIFIER) {\n                listResults.add(node)\n            }\n        }\n        val listTypes = firstNode?.findAllDescendantsWithSpecificType(IDENTIFIER)\n        Assertions.assertEquals(listResults, listTypes)\n    }\n\n    @Test\n    fun `test findParentNodeWithSpecificType`() {\n        val code = \"\"\"\n            val a = \"\"\n            class Test() {\n                fun foo() {\n                    try {\n                    } catch (e: Exception) {\n                    }\n                }\n            }\n        \"\"\".trimIndent()\n        val listResults: MutableList<ASTNode> = mutableListOf()\n        applyToCode(code, 0) { node, _ ->\n            if (node.elementType == IDENTIFIER) {\n                listResults.add(node)\n            }\n        }\n\n        listResults.forEach { node ->\n            if (node.findParentNodeWithSpecificType(KtNodeTypes.CATCH) == null) {\n                val identifiers = listOf(\"Test\", \"foo\", \"a\")\n                Assertions.assertTrue(identifiers.contains(node.text)) { \"Identifier <${node.text}> expected not to have CATCH parent node\" }\n            } else {\n                val identifiers = listOf(\"e\", \"Exception\")\n                Assertions.assertTrue(identifiers.contains(node.text)) { \"Identifier <${node.text}> expected to have CATCH parent node\" }\n            }\n        }\n    }\n\n    @Test\n    fun `test isAccessibleOutside`() {\n        val negativeExample = \"\"\"\n            class Test() {\n                /**\n                * test method\n                * @param a - dummy int\n                */\n                private fun foo(a: Int): Int = 2 * a\n            }\n        \"\"\".trimIndent()\n        applyToCode(negativeExample, 1) { node, counter ->\n            if (node.elementType == MODIFIER_LIST) {\n                Assertions.assertFalse(node.isAccessibleOutside())\n                counter.incrementAndGet()\n            }\n        }\n        val positiveExample = \"\"\"\n            class Test() {\n                /**\n                * test method\n                * @param a - dummy int\n                */\n                public fun foo(a: Int): Int = 2 * a\n            }\n        \"\"\".trimIndent()\n        applyToCode(positiveExample, 1) { node, counter ->\n            if (node.elementType == MODIFIER_LIST) {\n                Assertions.assertTrue(node.isAccessibleOutside())\n                counter.incrementAndGet()\n            }\n        }\n    }\n\n    @Test\n    fun `test leaveOnlyOneNewLine`() {\n        val code = \"\"\"\n            var x = 2\n\n\n        \"\"\".trimIndent()\n        applyToCode(code, 1) { node, counter ->\n            if (node.elementType == WHITE_SPACE && node.text.contains(\"\\n\\n\")) {\n                val parent = node.treeParent\n                val firstText = node.text\n                node.leaveOnlyOneNewLine()\n                val secondText = parent\n                    .getChildren(null)\n                    .last()\n                    .text\n                Assertions.assertEquals(\"\\n\", secondText)\n                Assertions.assertEquals(\"\\n\\n\", firstText)\n                counter.incrementAndGet()\n            }\n        }\n    }\n\n    @Test\n    fun `moveChildBefore 1 - reverse`() {\n        applyToCode(\"\"\"\n                |val a = 0\n                |val b = 1\n            \"\"\".trimMargin(), 5) { node, counter ->\n            if (node.getChildren(null).isNotEmpty()) {\n                val listBeforeMove = node.getChildren(null).map { it.elementType }\n                node.getChildren(null).forEachIndexed { index, astNode ->\n                    node.moveChildBefore(astNode, node.getChildren(null)[node.getChildren(null).size - index - 1])\n                }\n                val listAfterMove = node.getChildren(null).map { it.elementType }\n                Assertions.assertEquals(listBeforeMove, listAfterMove.reversed())\n                counter.incrementAndGet()\n            }\n        }\n    }\n\n    @Test\n    fun `moveChildBefore 2 - Should correctly move node child to the end`() {\n        applyToCode(\"\"\"\n                |val a = 0\n                |val b = 1\"\"\".trimMargin(), 1) { node, counter ->\n            if (node.elementType == KtFileElementType.INSTANCE) {\n                val val1 = node.getFirstChildWithType(PROPERTY)!!\n                val val2 = val1.nextSibling { it.elementType == PROPERTY }!!\n                node.moveChildBefore(val2, val1, true)\n                node.addChild(PsiWhiteSpaceImpl(\"\\n\"), val1)\n                Assertions.assertTrue(node.text == \"\"\"\n                    |val b = 1\n                    |val a = 0\n                    |\n                    \"\"\".trimMargin()\n                )\n                counter.incrementAndGet()\n            }\n        }\n    }\n\n    @Test\n    fun `isChildAfterGroup test`() {\n        applyToCode(\"val x = 0\", 1) { node, counter ->\n            if (node.elementType == PROPERTY) {\n                val valNode = node.getFirstChildWithType(VAL_KEYWORD)!!\n                val identifier = node.getFirstChildWithType(IDENTIFIER)!!\n                val eq = node.getFirstChildWithType(EQ)!!\n                val zero = node.getFirstChildWithType(INTEGER_CONSTANT)!!\n\n                Assertions.assertTrue(node.isChildAfterAnother(zero, valNode))\n                Assertions.assertTrue(node.isChildAfterGroup(zero, listOf(identifier, eq)))\n                Assertions.assertFalse(node.isChildAfterAnother(valNode, zero))\n                Assertions.assertFalse(node.isChildAfterGroup(identifier, listOf(zero, eq)))\n\n                Assertions.assertTrue(node.isChildBeforeAnother(identifier, zero))\n                Assertions.assertTrue(node.isChildBeforeGroup(identifier, listOf(eq, zero)))\n                Assertions.assertTrue(node.areChildrenBeforeChild(listOf(valNode, identifier, eq), zero))\n                Assertions.assertTrue(node.areChildrenBeforeGroup(listOf(valNode, identifier), listOf(eq, zero)))\n\n                Assertions.assertFalse(node.isChildBeforeAnother(zero, identifier))\n                Assertions.assertFalse(node.isChildBeforeGroup(zero, listOf(identifier, eq)))\n                Assertions.assertFalse(node.areChildrenBeforeChild(listOf(identifier, eq, zero), valNode))\n                Assertions.assertFalse(node.areChildrenBeforeGroup(listOf(eq, zero), listOf(valNode, identifier)))\n\n                counter.incrementAndGet()\n            }\n        }\n    }\n\n    @Test\n    fun `test line of text extraction`() {\n        applyToCode(\"\"\"\n            class Example {\n                fun\n                    foo() { }\n            }\n        \"\"\".trimIndent(), 1) { node, counter ->\n            if (node.elementType == IDENTIFIER && node.text == \"foo\") {\n                Assertions.assertEquals(\"foo() { }\", node.extractLineOfText())\n                counter.incrementAndGet()\n            }\n        }\n    }\n\n    @Test\n    @Suppress(\"TOO_LONG_FUNCTION\", \"TOO_MANY_LINES_IN_LAMBDA\")\n    fun `test lambda contains it`() {\n        applyToCode(\"\"\"\n            |fun bar(lambda: (s: String) -> Unit) {\n            |   lambda(\"bar\")\n            |}\n            |\n            |fun foo(lambda: (s: String) -> Unit) {\n            |   lambda(\"foo\")\n            |}\n            |\n            |fun test() {\n            |   // test1\n            |   foo { f1 ->\n            |       bar { b1 ->\n            |           println(f1 + \" -> \" + b1)\n            |       }\n            |   }\n            |   // test2\n            |   foo {\n            |       bar { b2 ->\n            |           println(it + \" -> \" + b2)\n            |       }\n            |   }\n            |   // test3\n            |   foo { f3 ->\n            |       bar {\n            |           println(f3 + \" -> \" + it)\n            |       }\n            |   }\n            |}\n        \"\"\".trimMargin(), 3) { node, counter ->\n            if (node.elementType == EOL_COMMENT) {\n                node.nextCodeSibling()\n                    ?.lastChildNode\n                    ?.firstChildNode\n                    ?.let {\n                        when (node.text) {\n                            \"// test1\" -> Assertions.assertFalse(doesLambdaContainIt(it))\n                            \"// test2\" -> Assertions.assertTrue(doesLambdaContainIt(it))\n                            \"// test3\" -> Assertions.assertFalse(doesLambdaContainIt(it))\n                            else -> {\n                                // this is a generated else block\n                            }\n                        }\n                        counter.incrementAndGet()\n                    }\n            }\n        }\n    }\n}\n\nprivate class PrettyPrintingVisitor(private val elementType: IElementType,\n                                    private val level: Int,\n                                    private val maxLevel: Int,\n                                    private val expected: String,\n) : DiktatRule {\n    override val id: String\n        get() = \"print-ast\"\n\n    override fun invoke(node: ASTNode, autoCorrect: Boolean, emitter: DiktatErrorEmitter) {\n        if (node.elementType == elementType) {\n            Assertions.assertEquals(\n                expected.replace(\"\\n\", System.lineSeparator()),\n                node.prettyPrint(level, maxLevel)\n            )\n        }\n    }\n\n    companion object {\n        fun assertStringRepr(\n            elementType: IElementType,\n            @Language(\"kotlin\") code: String,\n            level: Int = 0,\n            maxLevel: Int = -1,\n            expected: String\n        ) {\n            check(\n                ruleSetSupplier = { DiktatRuleSet(listOf(PrettyPrintingVisitor(elementType, level, maxLevel, expected))) },\n                text = code,\n            )\n        }\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/test/kotlin/com/saveourtool/diktat/ruleset/utils/AvailableRulesDocTest.kt",
    "content": "package com.saveourtool.diktat.ruleset.utils\n\nimport com.saveourtool.diktat.ruleset.constants.Warnings\nimport org.junit.jupiter.api.Assertions\nimport org.junit.jupiter.api.Test\nimport java.io.File\n\n/**\n * Special test to check that developer has not forgotten to write documentation for each warning.\n * Documentation should be added to available-rules.md\n */\nclass AvailableRulesDocTest {\n    private fun getAllRulesFromDoc(): List<String> {\n        val listWithRulesFromDoc: MutableList<String> = mutableListOf()\n        File(AVAILABLE_RULES_FILE).forEachLine { line ->\n            val splitMarkDown = line\n                .split(\"|\")\n\n            val ruleName = splitMarkDown[SPLIT_MARK].trim()\n\n            if (!ruleName.startsWith(TABLE_DELIMITER) &&\n                    !ruleName.startsWith(RULE_NAME_HEADER)) {\n                listWithRulesFromDoc.add(ruleName)\n            }\n        }\n        return listWithRulesFromDoc\n    }\n\n    @Test\n    fun `read rules from documentation`() {\n        val allRulesFromCode = Warnings.values().filterNot { it == Warnings.DUMMY_TEST_WARNING }\n        val allRulesFromDoc = getAllRulesFromDoc()\n\n        allRulesFromCode.forEach { warning ->\n            val ruleName = warning.ruleName()\n            val ruleFound = allRulesFromDoc.any { it.trim() == ruleName }\n            Assertions.assertTrue(ruleFound) {\n                val docs = \"| | | $ruleName\" +\n                        \"|  |  |  | |\"\n                \"\"\"\n                    Cannot find warning $ruleName in $AVAILABLE_RULES_FILE.\n                    You can fix it by adding the following description below with more info to $AVAILABLE_RULES_FILE:\n                    add $docs to $AVAILABLE_RULES_FILE\n                \"\"\"\n            }\n        }\n\n        allRulesFromDoc.forEach { warning ->\n            val trimmedWarning = warning.trim()\n            val ruleFound = allRulesFromCode.any { it.ruleName() == trimmedWarning }\n            Assertions.assertTrue(ruleFound) {\n                \"\"\"\n                    Found rule (warning) in documentation: <$trimmedWarning> that does not exist in the code. Misprint or configuration was renamed?\n                \"\"\".trimIndent()\n            }\n        }\n    }\n\n    companion object {\n        const val AVAILABLE_RULES_FILE = \"../info/available-rules.md\"\n        const val RULE_NAME_HEADER = \"Rule name\"\n        const val SPLIT_MARK = 3\n        const val TABLE_DELIMITER = \"-----\"\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/test/kotlin/com/saveourtool/diktat/ruleset/utils/FunctionAstNodeUtilsTest.kt",
    "content": "package com.saveourtool.diktat.ruleset.utils\n\nimport com.saveourtool.diktat.util.applyToCode\n\nimport org.jetbrains.kotlin.KtNodeTypes.FUN\nimport org.junit.jupiter.api.Assertions\nimport org.junit.jupiter.api.Test\n\n@Suppress(\"UnsafeCallOnNullableType\")\nclass FunctionAstNodeUtilsTest {\n    @Test\n    fun `should detect parameters in function - no parameters`() {\n        applyToCode(\"fun foo() { }\", 1) { node, counter ->\n            if (node.elementType == FUN) {\n                Assertions.assertFalse(node.hasParameters())\n                Assertions.assertTrue(node.parameterNames().isEmpty())\n                counter.incrementAndGet()\n            }\n        }\n    }\n\n    @Test\n    fun `should detect parameters in function`() {\n        applyToCode(\"fun foo(a: Int) { }\", 1) { node, counter ->\n            if (node.elementType == FUN) {\n                Assertions.assertTrue(node.hasParameters())\n                Assertions.assertEquals(listOf(\"a\"), node.parameterNames())\n                counter.incrementAndGet()\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/test/kotlin/com/saveourtool/diktat/ruleset/utils/KotlinParserTest.kt",
    "content": "package com.saveourtool.diktat.ruleset.utils\n\nimport com.saveourtool.diktat.util.applyToCode\n\nimport org.jetbrains.kotlin.KtNodeTypes.CALL_EXPRESSION\nimport org.jetbrains.kotlin.KtNodeTypes.CLASS\nimport org.jetbrains.kotlin.KtNodeTypes.CLASS_BODY\nimport org.jetbrains.kotlin.lexer.KtTokens.CLASS_KEYWORD\nimport org.jetbrains.kotlin.KtNodeTypes.FUN\nimport org.jetbrains.kotlin.KtNodeTypes.IMPORT_DIRECTIVE\nimport org.jetbrains.kotlin.lexer.KtTokens.IMPORT_KEYWORD\nimport org.jetbrains.kotlin.KtNodeTypes.IMPORT_LIST\nimport org.jetbrains.kotlin.kdoc.lexer.KDocTokens.KDOC\nimport org.jetbrains.kotlin.KtNodeTypes.PACKAGE_DIRECTIVE\nimport org.jetbrains.kotlin.KtNodeTypes.PROPERTY\nimport org.jetbrains.kotlin.lexer.KtTokens.RBRACE\nimport org.jetbrains.kotlin.KtNodeTypes.SECONDARY_CONSTRUCTOR\nimport org.jetbrains.kotlin.lexer.KtTokens.WHITE_SPACE\nimport org.jetbrains.kotlin.com.intellij.lang.ASTNode\nimport org.jetbrains.kotlin.com.intellij.psi.impl.source.tree.PsiWhiteSpaceImpl\nimport org.jetbrains.kotlin.psi.stubs.elements.KtFileElementType\nimport org.junit.jupiter.api.Assertions\nimport org.junit.jupiter.api.Test\nimport org.junit.jupiter.api.assertThrows\n\nclass KotlinParserTest {\n    @Test\n    fun `test simple property`() {\n        val node = KotlinParser().createNode(\"val x: Int = 10\")\n        Assertions.assertEquals(PROPERTY, node.elementType)\n        Assertions.assertEquals(\"val x: Int = 10\", node.text)\n        Assertions.assertEquals(4, node.findAllDescendantsWithSpecificType(WHITE_SPACE).size)\n    }\n\n    @Test\n    @Suppress(\"UnsafeCallOnNullableType\")\n    fun `test oneline function`() {\n        val node = KotlinParser().createNode(\"fun foo(text: String) = text.toUpperCase()\")\n        Assertions.assertEquals(FUN, node.elementType)\n        Assertions.assertEquals(\"fun foo(text: String) = text.toUpperCase()\", node.text)\n        Assertions.assertEquals(\"foo\", node.getIdentifierName()!!.text)\n        Assertions.assertEquals(4, node.findAllDescendantsWithSpecificType(WHITE_SPACE).size)\n    }\n\n    @Test\n    fun `test invalidate code`() {\n        assertThrows<KotlinParseException> { KotlinParser().createNode(\"simple text\") }\n        assertThrows<KotlinParseException> { KotlinParser().createNode(\"\") }\n        assertThrows<KotlinParseException> { KotlinParser().createNode(\"fuc fun() = 1\") }\n    }\n\n    @Test\n    fun `test multiline code with import and package`() {\n        val code = \"\"\"\n            |package com.saveourtool.diktat.ruleset.utils\n            |\n            |import org.junit.jupiter.api.Test\n            |import org.junit.jupiter.api.Tests\n            |\n            |class A {\n            |   fun foo(){\n            |       println(\"hello\")\n            |   }\n            |}\n            \"\"\".trimMargin()\n        val node = KotlinParser().createNode(code, true)\n        Assertions.assertEquals(KtFileElementType.INSTANCE, node.elementType)\n        Assertions.assertEquals(PACKAGE_DIRECTIVE, node.firstChildNode.elementType)\n    }\n\n    @Test\n    fun `test multiline class code`() {\n        val code = \"\"\"\n            |class A {\n            |   fun foo(){\n            |       println(\"hello\")\n            |   }\n            |}\n            \"\"\".trimMargin()\n        val node = KotlinParser().createNode(code)\n        Assertions.assertEquals(CLASS, node.elementType)\n        Assertions.assertEquals(CLASS_KEYWORD, node.firstChildNode.elementType)\n    }\n\n    @Test\n    fun `test multiline class code with import`() {\n        val code = \"\"\"\n            |import org.junit.jupiter.api.Test\n            |import org.junit.jupiter.api.Tests\n            |\n            |class A {\n            |   fun foo(){\n            |       println(\"hello\")\n            |   }\n            |}\n            \"\"\".trimMargin()\n        assertThrows<KotlinParseException> { KotlinParser().createNode(code) }\n    }\n\n    @Test\n    @Suppress(\n        \"UnsafeCallOnNullableType\",\n        \"TOO_LONG_FUNCTION\",\n        \"AVOID_NULL_CHECKS\"\n    )\n    fun `test multiline class code compare with applyToCode`() {\n        val emptyClass = \"\"\"\n            |package com.saveourtool.diktat.ruleset.utils\n            |\n            |import org.junit.jupiter.api.Test\n            |\n            |class A {\n            |}\n            \"\"\".trimMargin()\n        var nodeToApply: ASTNode? = null\n        applyToCode(emptyClass, 0) { newNode, _ ->\n            if (nodeToApply == null) {\n                nodeToApply = newNode\n            }\n        }\n        val resultClass = \"\"\"\n            |package com.saveourtool.diktat.ruleset.utils\n            |\n            |import org.junit.jupiter.api.Test\n            |\n            |class A {\n            |fun foo() = \"Hello\"\n            |}\n            \"\"\".trimMargin()\n        var resultNode: ASTNode? = null\n        applyToCode(resultClass, 0) { newNode, _ ->\n            if (resultNode == null) {\n                resultNode = newNode\n            }\n        }\n        Assertions.assertTrue(nodeToApply!!.prettyPrint() == KotlinParser().createNode(emptyClass, true).prettyPrint())\n        val classNode = nodeToApply!!.findChildByType(CLASS)!!.findChildByType(CLASS_BODY)!!\n        val function = \"\"\"\n            |fun foo() = \"Hello\"\n            \"\"\".trimMargin()\n        classNode.addChild(KotlinParser().createNode(function), classNode.findChildByType(RBRACE))\n        classNode.addChild(PsiWhiteSpaceImpl(\"\\n\"), classNode.findChildByType(RBRACE))\n        Assertions.assertTrue(nodeToApply!!.prettyPrint() == resultNode!!.prettyPrint())\n    }\n\n    @Test\n    fun `check package`() {\n        val packageCode = \"\"\"\n            |package com.saveourtool.diktat.ruleset.utils\n            \"\"\".trimMargin()\n        val node = KotlinParser().createNode(packageCode, true)\n        Assertions.assertEquals(KtFileElementType.INSTANCE, node.elementType)\n        Assertions.assertEquals(packageCode, node.text)\n        Assertions.assertEquals(PACKAGE_DIRECTIVE, node.firstChildNode.elementType)\n    }\n\n    @Test\n    fun `check import`() {\n        val importCode = \"\"\"\n            |import org.junit.jupiter.api.Test\n            \"\"\".trimMargin()\n        val node = KotlinParser().createNode(importCode)\n        Assertions.assertEquals(IMPORT_DIRECTIVE, node.elementType)\n        Assertions.assertEquals(importCode, node.text)\n        Assertions.assertEquals(IMPORT_KEYWORD, node.firstChildNode.elementType)\n    }\n\n    @Test\n    fun `check imports`() {\n        val importCode = \"\"\"\n            |import org.junit.jupiter.api.Test\n            |import org.junit.jupiter.api.Tests\n            |import org.junit.jupiter.api\n            \"\"\".trimMargin()\n        val node = KotlinParser().createNode(importCode)\n        Assertions.assertEquals(IMPORT_LIST, node.elementType)\n        Assertions.assertEquals(importCode, node.text)\n        Assertions.assertEquals(IMPORT_DIRECTIVE, node.firstChildNode.elementType)\n    }\n\n    @Test\n    fun `check package and import`() {\n        val code = \"\"\"\n            |package com.saveourtool.diktat.ruleset.utils\n            |\n            |import org.junit.jupiter.api.Test\n            |import org.junit.jupiter.api.Tests\n            \"\"\".trimMargin()\n        val node = KotlinParser().createNode(code, true)\n        Assertions.assertEquals(KtFileElementType.INSTANCE, node.elementType)\n        Assertions.assertEquals(code, node.text)\n        Assertions.assertEquals(PACKAGE_DIRECTIVE, node.firstChildNode.elementType)\n    }\n\n    @Test\n    @Suppress(\"UnsafeCallOnNullableType\")\n    fun `check KDoc`() {\n        val code = \"\"\"\n            |/**\n            |* [link]haha\n            |*/\n            |fun foo()\n            \"\"\".trimMargin()\n        val node = KotlinParser().createNode(code)\n        Assertions.assertEquals(KDOC, node.findChildByType(FUN)!!.firstChildNode.elementType)\n\n        val kdocText = \"\"\"\n            /**\n            * [link]haha\n            */\n        \"\"\".trimIndent()\n        Assertions.assertEquals(kdocText, node.findChildByType(FUN)!!.firstChildNode.text)\n    }\n\n    @Test\n    fun `test createNodeForInit`() {\n        val code = \"\"\"\n            |init {\n            |   println(\"A\")\n            |   // import is a weak keyword\n            |   println(\"B\")\n            |}\n            \"\"\".trimMargin()\n        val node = KotlinParser().createNodeForInit(code)\n        Assertions.assertEquals(CALL_EXPRESSION, node.elementType)\n        Assertions.assertEquals(code, node.text)\n    }\n\n    @Test\n    fun `test createNodeForSecondaryConstructor`() {\n        val code = \"\"\"\n            |constructor(a: Int) {\n            |   // import is a weak keyword\n            |   b = a.toString()\n            |}\n            \"\"\".trimMargin()\n        val node = KotlinParser().createNodeForSecondaryConstructor(code)\n        Assertions.assertEquals(SECONDARY_CONSTRUCTOR, node.elementType)\n        Assertions.assertEquals(code, node.text)\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/test/kotlin/com/saveourtool/diktat/ruleset/utils/RulesConfigYamlTest.kt",
    "content": "package com.saveourtool.diktat.ruleset.utils\n\nimport com.saveourtool.diktat.common.config.rules.DIKTAT_COMMON\nimport com.saveourtool.diktat.common.config.rules.RulesConfig\nimport com.saveourtool.diktat.ruleset.config.kotlinVersion\nimport com.saveourtool.diktat.ruleset.config.DiktatRuleConfigYamlReader\nimport com.saveourtool.diktat.common.config.rules.getRuleConfig\nimport com.saveourtool.diktat.ruleset.constants.Warnings\n\nimport com.charleskorn.kaml.Yaml\nimport org.junit.jupiter.api.Assertions\nimport org.junit.jupiter.api.Test\n\nimport java.io.File\nimport java.nio.file.Paths\nimport kotlin.io.path.exists\nimport kotlin.io.path.inputStream\n\nimport kotlinx.serialization.encodeToString\n\n/**\n * Special test that checks that developer has not forgotten to add his warning to a diktat-analysis.yml\n * This file is needed to be in tact with latest changes in Warnings.kt\n */\n@Suppress(\"UNUSED\")\nclass RulesConfigYamlTest {\n    private val parentDiktatAnalysis = \"${System.getProperty(\"user.dir\")}${File.separator}..${File.separator}diktat-analysis.yml${File.separator}\"\n    private val pathMap: Map<String, String> =\n        mapOf(\"diktat-analysis.yml\" to \"diKTat/diktat-rules/src/main/resources/diktat-analysis.yml\",\n            \"diktat-analysis-huawei.yml\" to \"diKTat/diktat-rules/src/main/resources/diktat-analysis-huawei.yml\",\n            parentDiktatAnalysis to \"diKTat/diktat-analysis.yml\")\n\n    @Test\n    fun `read rules config yml`() {\n        compareRulesAndConfig(\"diktat-analysis.yml\")\n        compareRulesAndConfig(\"diktat-analysis-huawei.yml\")\n        compareRulesAndConfig(parentDiktatAnalysis, \"diKTat/diktat-analysis.yml\")\n    }\n\n    @Test\n    fun `check comments before rules`() {\n        checkComments(\"src/main/resources/diktat-analysis.yml\")\n        checkComments(\"src/main/resources/diktat-analysis-huawei.yml\")\n        checkComments(\"../diktat-analysis.yml\")\n    }\n\n    @Test\n    @Suppress(\"UNUSED\")\n    fun `check kotlin version`() {\n        val currentKotlinVersion = \"${KotlinVersion.CURRENT.major}.${KotlinVersion.CURRENT.minor}\"\n        pathMap.keys.forEach { path ->\n            val config = readAllRulesFromConfig(path)\n            val ktVersion = config.find { it.name == DIKTAT_COMMON }\n                ?.configuration\n                ?.get(\"kotlinVersion\")\n                ?.kotlinVersion()\n            val ktVersionNew = \"${ktVersion?.major}.${ktVersion?.minor}\"\n            Assertions.assertEquals(ktVersionNew, currentKotlinVersion)\n        }\n    }\n\n    private fun checkComments(configName: String) {\n        val lines = File(configName)\n            .readLines()\n            .filter {\n                it.startsWith(\"-\") || it.startsWith(\"#\")\n            }\n\n        lines.forEachIndexed { index, str ->\n            if (str.startsWith(\"-\")) {\n                Assertions.assertTrue(lines[if (index > 0) index - 1 else 0].trim().startsWith(\"#\")) {\n                    \"\"\"\n                        There is no comment before $str in $configName\n                    \"\"\".trimIndent()\n                }\n            }\n        }\n    }\n\n    private fun compareRulesAndConfig(nameConfig: String, nameConfigToText: String? = null) {\n        val filePath = nameConfigToText?.let { pathMap[it] } ?: pathMap[nameConfig]\n        val allRulesFromConfig = readAllRulesFromConfig(nameConfig)\n        val allRulesFromCode = readAllRulesFromCode()\n\n        allRulesFromCode.forEach { rule ->\n            if (rule == Warnings.DUMMY_TEST_WARNING) {\n                return@forEach\n            }\n            val foundRule = allRulesFromConfig.getRuleConfig(rule)\n            val ymlCodeSnippet = RulesConfig(rule.ruleName(), true, emptyMap())\n\n            val ruleYaml = Yaml.default.encodeToString(ymlCodeSnippet)\n            Assertions.assertTrue(foundRule != null) {\n                \"\"\"\n                   Cannot find warning ${rule.ruleName()} in $filePath.\n                   You can fix it by adding the following code below to $filePath:\n                   $ruleYaml\n                \"\"\".trimIndent()\n            }\n        }\n\n        allRulesFromConfig.forEach { warning ->\n            val warningName = warning.name\n            val ruleFound = allRulesFromCode.any { it.ruleName() == warningName || warningName == \"DIKTAT_COMMON\" }\n            Assertions.assertTrue(ruleFound) {\n                \"\"\"\n                    Found rule (warning) in $filePath: <$warningName> that does not exist in the code. Misprint or configuration was renamed?\n                \"\"\".trimIndent()\n            }\n        }\n    }\n\n    private fun readAllRulesFromConfig(nameConfig: String) = run {\n        Paths.get(nameConfig).takeIf { it.exists() }?.inputStream()\n            ?: javaClass.classLoader.getResourceAsStream(nameConfig)\n    }\n        ?.let { DiktatRuleConfigYamlReader().invoke(it) }\n        ?: emptyList()\n\n    private fun readAllRulesFromCode() =\n        Warnings.values()\n}\n"
  },
  {
    "path": "diktat-rules/src/test/kotlin/com/saveourtool/diktat/ruleset/utils/StringCaseUtilsTest.kt",
    "content": "package com.saveourtool.diktat.ruleset.utils\n\nimport org.junit.jupiter.api.Assertions\nimport org.junit.jupiter.api.Test\n\nclass StringCaseUtilsTest {\n    @Test\n    fun `check conversion to upperSnakeCase`() {\n        Assertions.assertEquals(\"PASCAL_CASE\", \"PascalCase\".toUpperSnakeCase())\n        Assertions.assertEquals(\"LOWER_SNAKE\", \"lower_snake\".toUpperSnakeCase())\n        Assertions.assertEquals(\"I_AM_CONSTANT\", \"iAmConstant\".toUpperSnakeCase())\n        Assertions.assertEquals(\"PASCAL_N_CASE\", \"PascalN_Case\".toUpperSnakeCase())\n    }\n\n    @Test\n    fun `check conversion to lowerCamelCase`() {\n        Assertions.assertEquals(\"strangeName\", \"STRANGE_name\".toLowerCamelCase())\n        Assertions.assertEquals(\"strangeName\", \"STRANGE_NAME\".toLowerCamelCase())\n        Assertions.assertEquals(\"sTrangeName\", \"sTrange_NAME\".toLowerCamelCase())\n        Assertions.assertEquals(\"sTrangeName\", \"sTRange_NAME\".toLowerCamelCase())\n        Assertions.assertEquals(\"sTrangeName\", \"__sTRange_NAME\".toLowerCamelCase())\n        Assertions.assertEquals(\"pascalNCase\", \"PascalN_Case\".toLowerCamelCase())\n    }\n\n    @Test\n    fun `check conversion to PascalCase`() {\n        Assertions.assertEquals(\"StrangeName\", \"STRANGE_name\".toPascalCase())\n        Assertions.assertEquals(\"StrangeName\", \"STRANGE_NAME\".toPascalCase())\n        Assertions.assertEquals(\"StrangeName\", \"sTrange_NAME\".toPascalCase())\n        Assertions.assertEquals(\"KdocTest\", \"KDoc_test\".toPascalCase())\n        Assertions.assertEquals(\"StrangeName\", \"sTRange_NAME\".toPascalCase())\n        Assertions.assertEquals(\"StrangeName\", \"__sTRange_NAME\".toPascalCase())\n        Assertions.assertEquals(\"PascalNCase\", \"PascalN_Case\".toPascalCase())\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/test/kotlin/com/saveourtool/diktat/ruleset/utils/SuppressAnnotatedExpressionTest.kt",
    "content": "package com.saveourtool.diktat.ruleset.utils\n\nimport com.saveourtool.diktat.common.config.rules.DIKTAT_RULE_SET_ID\nimport com.saveourtool.diktat.ruleset.constants.Warnings\nimport com.saveourtool.diktat.ruleset.rules.chapter3.CollapseIfStatementsRule\nimport com.saveourtool.diktat.util.LintTestBase\n\nimport com.saveourtool.diktat.api.DiktatError\nimport org.junit.jupiter.api.Test\n\nclass SuppressAnnotatedExpressionTest : LintTestBase(::CollapseIfStatementsRule) {\n    private val ruleId: String = \"$DIKTAT_RULE_SET_ID:${CollapseIfStatementsRule.NAME_ID}\"\n\n    @Test\n    fun `should lint errors without suppress`() {\n        val code =\n            \"\"\"\n                |fun foo() {\n                |   if (true) {\n                |       if (true) {\n                |           if (true) {\n                |\n                |           }\n                |       }\n                |   }\n                |}\n            \"\"\".trimMargin()\n        lintMethod(code,\n            DiktatError(3, 8, ruleId, \"${Warnings.COLLAPSE_IF_STATEMENTS.warnText()} avoid using redundant nested if-statements\", true),\n            DiktatError(4, 12, ruleId, \"${Warnings.COLLAPSE_IF_STATEMENTS.warnText()} avoid using redundant nested if-statements\", true)\n        )\n    }\n\n    @Test\n    fun `should suppress annotated expressions`() {\n        val code =\n            \"\"\"\n                |fun foo() {\n                |   if (true) {\n                |       @Suppress(\"COLLAPSE_IF_STATEMENTS\")\n                |       if (true) {\n                |           if (true) {\n                |\n                |           }\n                |       }\n                |   }\n                |}\n            \"\"\".trimMargin()\n        lintMethod(code)\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/test/kotlin/com/saveourtool/diktat/ruleset/utils/SuppressTest.kt",
    "content": "package com.saveourtool.diktat.ruleset.utils\n\nimport com.saveourtool.diktat.common.config.rules.DIKTAT_RULE_SET_ID\nimport com.saveourtool.diktat.ruleset.constants.Warnings\nimport com.saveourtool.diktat.ruleset.rules.chapter1.IdentifierNaming\nimport com.saveourtool.diktat.util.LintTestBase\n\nimport com.saveourtool.diktat.api.DiktatError\nimport org.junit.jupiter.api.Test\n\nclass SuppressTest : LintTestBase(::IdentifierNaming) {\n    private val ruleId: String = \"$DIKTAT_RULE_SET_ID:${IdentifierNaming.NAME_ID}\"\n\n    @Test\n    fun `test suppress on class`() {\n        val code =\n            \"\"\"\n                @Suppress(\"FUNCTION_NAME_INCORRECT_CASE\", \"BACKTICKS_PROHIBITED\")\n                class SomeClass {\n                    fun /* */ methODTREE(): String {\n\n                    }\n\n                    fun `some`() {}\n                }\n            \"\"\".trimIndent()\n        lintMethod(code)\n    }\n\n    @Test\n    fun `check suppress on method`() {\n        lintMethod(\n            \"\"\"\n                    |class SomeClass {\n                    |\n                    |   @Suppress(\"FUNCTION_NAME_INCORRECT_CASE\")\n                    |   fun /* */ methODTREE(): String {\n                    |\n                    |       fun soMEMETHOD() {\n                    |\n                    |       }\n                    |\n                    |   }\n                    |\n                    |   fun /* */ methODTREEASA(): String {\n                    |\n                    |   }\n                    |}\n            \"\"\".trimMargin(),\n            DiktatError(12, 14, ruleId, \"${Warnings.FUNCTION_NAME_INCORRECT_CASE.warnText()} methODTREEASA\",\n                true)\n        )\n    }\n\n    @Test\n    fun `check suppress on variable`() {\n        lintMethod(\n            \"\"\"\n                    |class SomeClass {\n                    |\n                    |   @Suppress(\"FUNCTION_NAME_INCORRECT_CASE\")\n                    |   fun /* */ methODTREE(): String {\n                    |       @Suppress( \"VARIABLE_NAME_INCORRECT_FORMAT\" )\n                    |       var SOMEvar = 5\n                    |   }\n                    |}\n            \"\"\".trimMargin()\n        )\n    }\n\n    @Test\n    fun `test suppress on file`() {\n        val code =\n            \"\"\"\n                @file:Suppress(\"FUNCTION_NAME_INCORRECT_CASE\")\n\n                class SomeClass {\n                    fun /* */ methODTREE(): String {\n\n                    }\n                }\n            \"\"\".trimIndent()\n        lintMethod(code)\n    }\n\n    @Test\n    fun `test suppress field`() {\n        val code =\n            \"\"\"\n                class SomeClass(@field:Suppress(\"IDENTIFIER_LENGTH\") val a:String) {\n                    fun /* */ method(): String {\n\n                    }\n                }\n            \"\"\".trimIndent()\n        lintMethod(code)\n    }\n\n    @Test\n    fun `test suppress field with set`() {\n        val code =\n            \"\"\"\n                class SomeClass() {\n                    @set:[Suppress(\"IDENTIFIER_LENGTH\") Inject]\n                    val a = 5\n\n                    fun /* */ method(): String {\n\n                    }\n                }\n            \"\"\".trimIndent()\n        lintMethod(code)\n    }\n\n    @Test\n    fun `check simple wrong enum`() {\n        lintMethod(\n            \"\"\"\n                    |@set:[Suppress(\"WRONG_DECLARATION_ORDER\") Suppress(\"IDENTIFIER_LENGTH\") Suppress(\"CONFUSING_IDENTIFIER_NAMING\")]\n                    |enum class Alph {\n                    |   D,\n                    |   C,\n                    |   A,\n                    |   B,\n                    |   ;\n                    |}\n            \"\"\".trimMargin()\n        )\n    }\n\n    @Test\n    fun `test suppress on class bad`() {\n        val code =\n            \"\"\"\n                @Suppress()\n                class SomeClass {\n                    fun /* */ methODTREE(): String {\n\n                    }\n                }\n            \"\"\".trimIndent()\n        lintMethod(code,\n            DiktatError(3, 15, \"$DIKTAT_RULE_SET_ID:${IdentifierNaming.NAME_ID}\",\n                \"${Warnings.FUNCTION_NAME_INCORRECT_CASE.warnText()} methODTREE\", true))\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/test/kotlin/com/saveourtool/diktat/ruleset/utils/VariablesSearchTest.kt",
    "content": "package com.saveourtool.diktat.ruleset.utils\n\nimport com.saveourtool.diktat.ruleset.utils.search.VariablesSearch\nimport com.saveourtool.diktat.ruleset.utils.search.default\nimport com.saveourtool.diktat.util.applyToCode\nimport org.jetbrains.kotlin.psi.KtElement\nimport org.jetbrains.kotlin.psi.KtNameReferenceExpression\nimport org.jetbrains.kotlin.psi.KtProperty\n\nimport org.jetbrains.kotlin.psi.stubs.elements.KtFileElementType\nimport org.junit.jupiter.api.Assertions\nimport org.junit.jupiter.api.Assertions.assertTrue\nimport org.junit.jupiter.api.Test\n\n@Suppress(\"UnsafeCallOnNullableType\")\nclass VariablesSearchTest {\n    @Test\n    fun `testing requirement for collecting variables`() {\n        applyToCode(\"\"\"\n            fun foo(a: Int) {\n                fun foo1() {\n                    var o = 1\n                    b = o\n                    c = o\n                    o = 15\n                    o = 17\n                }\n            }\n        \"\"\".trimIndent(), 0) { node, _ ->\n            if (node.elementType != KtFileElementType.INSTANCE) {\n                val variablesSearchAbstract: VariablesSearch = object : VariablesSearch(node, ::default) {\n                    override fun KtElement.getAllSearchResults(property: KtProperty): List<KtNameReferenceExpression> = TODO(\"Not required for test\")\n                }\n\n                val thrown = Assertions.assertThrows(IllegalArgumentException::class.java) {\n                    variablesSearchAbstract.collectVariables()\n                }\n                assertTrue(thrown.message!!.contains(\"To collect all variables in a file you need to provide file root node\"))\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/test/kotlin/com/saveourtool/diktat/ruleset/utils/VariablesWithAssignmentsSearchTest.kt",
    "content": "package com.saveourtool.diktat.ruleset.utils\n\nimport com.saveourtool.diktat.ruleset.utils.search.findAllVariablesWithAssignments\nimport com.saveourtool.diktat.util.applyToCode\nimport org.jetbrains.kotlin.psi.stubs.elements.KtFileElementType\n\nimport org.junit.jupiter.api.Assertions\nimport org.junit.jupiter.api.Disabled\nimport org.junit.jupiter.api.Test\n\n@Suppress(\"UnsafeCallOnNullableType\")\nclass VariablesWithAssignmentsSearchTest {\n    @Test\n    fun `testing proper variables search in function`() {\n        applyToCode(\"\"\"\n            fun foo(a: Int) {\n                fun foo1() {\n                    var o = 1\n                    b = o\n                    c = o\n                    o = 15\n                    o = 17\n                }\n            }\n        \"\"\".trimIndent(), 0) { node, _ ->\n            if (node.elementType == KtFileElementType.INSTANCE) {\n                val vars = node.findAllVariablesWithAssignments().mapKeys { it.key.text }\n                val keys = vars.keys\n                val var1 = keys.elementAt(0)\n                Assertions.assertEquals(\"var o = 1\", var1)\n                Assertions.assertEquals(2, vars[var1]?.size)\n            }\n        }\n    }\n\n    @Test\n    fun `testing proper variables search in class`() {\n        applyToCode(\"\"\"\n            class A {\n                var o = 1\n                fun foo(a: Int) {\n                    fun foo1() {\n                        b = o\n                        c = o\n                        d = o\n                        o = 15\n                        o = 17\n                    }\n                }\n            }\n        \"\"\".trimIndent(), 0) { node, _ ->\n            if (node.elementType == KtFileElementType.INSTANCE) {\n                val vars = node.findAllVariablesWithAssignments().mapKeys { it.key.text }\n                val keys = vars.keys\n                val var1 = keys.elementAt(0)\n                Assertions.assertEquals(\"var o = 1\", var1)\n                Assertions.assertEquals(2, vars[var1]?.size)\n            }\n        }\n    }\n\n    @Test\n    @Disabled\n    fun `testing proper variables search with lambda`() {\n        applyToCode(\"\"\"\n                fun foo(a: Int) {\n                    var a = 1\n                    a++\n                }\n        \"\"\".trimIndent(), 0) { node, _ ->\n            if (node.elementType == KtFileElementType.INSTANCE) {\n                val vars = node.findAllVariablesWithAssignments().mapKeys { it.key.text }\n                val keys = vars.keys\n                val var1 = keys.elementAt(0)\n                Assertions.assertEquals(\"var a = 1\", var1)\n                Assertions.assertEquals(1, vars[var1]?.size)\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/test/kotlin/com/saveourtool/diktat/ruleset/utils/VariablesWithUsagesSearchTest.kt",
    "content": "package com.saveourtool.diktat.ruleset.utils\n\nimport com.saveourtool.diktat.ruleset.utils.search.findAllVariablesWithUsages\nimport com.saveourtool.diktat.util.applyToCode\nimport org.jetbrains.kotlin.psi.stubs.elements.KtFileElementType\n\nimport org.junit.jupiter.api.Assertions.assertEquals\nimport org.junit.jupiter.api.Disabled\nimport org.junit.jupiter.api.Test\n\n@Suppress(\"UnsafeCallOnNullableType\")\nclass VariablesWithUsagesSearchTest {\n    @Test\n    fun `testing proper variables search in function`() {\n        applyToCode(\"\"\"\n            fun foo(a: Int) {\n                fun foo1() {\n                    val o = 1\n                    val a = 2\n                    println(a.o)\n                }\n            }\n        \"\"\".trimIndent(), 0) { node, _ ->\n            if (node.elementType == KtFileElementType.INSTANCE) {\n                val vars = node.findAllVariablesWithUsages().mapKeys { it.key.text }\n                val keys = vars.keys\n                val var1 = keys.elementAt(0)\n                val var2 = keys.elementAt(1)\n                assertEquals(\"val o = 1\", var1)\n                assertEquals(0, vars[var1]?.size)\n                assertEquals(\"val a = 2\", var2)\n                assertEquals(1, vars[var2]?.size)\n            }\n        }\n    }\n\n    @Test\n    fun `testing proper variables search in function with false positive shadowing`() {\n        applyToCode(\"\"\"\n            fun foo() {\n                var v = 1\n                if (true) {\n                    v++\n                    var v = 0\n                }\n            }\n        \"\"\".trimIndent(), 0) { node, _ ->\n            if (node.elementType == KtFileElementType.INSTANCE) {\n                val vars = node.findAllVariablesWithUsages().mapKeys { it.key.text }\n                val keys = vars.keys\n                val var1 = keys.elementAt(0)\n                val var2 = keys.elementAt(1)\n                assertEquals(\"var v = 1\", var1)\n                assertEquals(1, vars[var1]?.size)\n                assertEquals(\"var v = 0\", var2)\n                assertEquals(0, vars[var2]?.size)\n            }\n        }\n    }\n\n    @Test\n    fun `testing proper variables search in function with false positive shadowing and nesting`() {\n        applyToCode(\"\"\"\n            fun foo() {\n                var v = 1\n                if (true) {\n                    if (true) {\n                        v++\n                    }\n                    var v = 0\n                }\n            }\n        \"\"\".trimIndent(), 0) { node, _ ->\n            if (node.elementType == KtFileElementType.INSTANCE) {\n                val vars = node.findAllVariablesWithUsages().mapKeys { it.key.text }\n                val keys = vars.keys\n                val var1 = keys.elementAt(0)\n                val var2 = keys.elementAt(1)\n                assertEquals(\"var v = 1\", var1)\n                assertEquals(1, vars[var1]?.size)\n                assertEquals(\"var v = 0\", var2)\n                assertEquals(0, vars[var2]?.size)\n            }\n        }\n    }\n\n    @Test\n    fun `testing proper variables search in simple class with property`() {\n        applyToCode(\"\"\"\n            class A {\n                val v = 0\n                fun foo() {\n                    ++v\n                }\n            }\n        \"\"\".trimIndent(), 0) { node, _ ->\n            if (node.elementType == KtFileElementType.INSTANCE) {\n                val vars = node.findAllVariablesWithUsages().mapKeys { it.key.text }\n                val keys = vars.keys\n                val var1 = keys.elementAt(0)\n                assertEquals(\"val v = 0\", var1)\n                assertEquals(1, vars[var1]?.size)\n            }\n        }\n    }\n\n    @Test\n    @Disabled\n    // FixMe: very strange behavior of Kotlin\n    fun `testing proper variables search in function with a class nested in a function`() {\n        applyToCode(\"\"\"\n            fun foo() {\n                var a = 0\n                class A {\n                    var a = 1\n                    fun foo() {\n                        a++\n                    }\n                }\n            }\n        \"\"\".trimIndent(), 0) { node, _ ->\n            if (node.elementType == KtFileElementType.INSTANCE) {\n                val vars = node.findAllVariablesWithUsages().mapKeys { it.key.text }\n                val keys = vars.keys\n                val var1 = keys.elementAt(0)\n                val var2 = keys.elementAt(1)\n                assertEquals(\"var a = 0\", var1)\n                assertEquals(1, vars[var1]?.size)\n                assertEquals(\"var a = 1\", var2)\n                assertEquals(0, vars[var2]?.size)\n            }\n        }\n    }\n\n    @Test\n    fun `testing proper variables search in class`() {\n        applyToCode(\"\"\"\n            class SomeClass {\n                val someVal = 0\n                fun foo(a: Int) {\n                    someVal++\n                }\n            }\n        \"\"\".trimIndent(), 0) { node, _ ->\n            if (node.elementType == KtFileElementType.INSTANCE) {\n                val vars = node.findAllVariablesWithUsages().mapKeys { it.key.text }\n                val keys = vars.keys\n                val var1 = keys.elementAt(0)\n                assertEquals(\"val someVal = 0\", var1)\n                assertEquals(1, vars[var1]?.size)\n            }\n        }\n    }\n\n    @Test\n    fun `testing proper variables search in class and global context`() {\n        applyToCode(\"\"\"\n            val someVal = 1\n            class SomeClass {\n                val someVal = 0\n                fun foo(a: Int) {\n                    someVal++\n                }\n            }\n        \"\"\".trimIndent(), 0) { node, _ ->\n            if (node.elementType == KtFileElementType.INSTANCE) {\n                val vars = node.findAllVariablesWithUsages().mapKeys { it.key.text }\n                val keys = vars.keys\n                val var1 = keys.elementAt(0)\n                val var2 = keys.elementAt(1)\n                assertEquals(\"val someVal = 1\", var1)\n                assertEquals(0, vars[var1]?.size)\n                assertEquals(\"val someVal = 0\", var2)\n                assertEquals(1, vars[var2]?.size)\n            }\n        }\n    }\n\n    @Test\n    fun `testing proper variables search in a nested class that is inside of a function`() {\n        applyToCode(\"\"\"\n            fun foo(a: Int) {\n                class A {\n                    var a = 5\n                    fun foo() {\n                        println(a)\n                    }\n                }\n            }\n        \"\"\".trimIndent(), 0) { node, _ ->\n            if (node.elementType == KtFileElementType.INSTANCE) {\n                val vars = node.findAllVariablesWithUsages().mapKeys { it.key.text }\n                val keys = vars.keys\n                val var1 = keys.elementAt(0)\n                assertEquals(\"var a = 5\", var1)\n                assertEquals(0, vars[var1]?.size)\n            }\n        }\n    }\n\n    @Test\n    fun `testing proper variables search in a nested functions`() {\n        applyToCode(\"\"\"\n            fun foo(a: Int) {\n                fun foo() {\n                    var a = 5\n                    println(a)\n                }\n            }\n        \"\"\".trimIndent(), 0) { node, _ ->\n            if (node.elementType == KtFileElementType.INSTANCE) {\n                val vars = node.findAllVariablesWithUsages().mapKeys { it.key.text }\n                val keys = vars.keys\n                val var1 = keys.elementAt(0)\n                assertEquals(\"var a = 5\", var1)\n                assertEquals(1, vars[var1]?.size)\n            }\n        }\n    }\n\n    @Test\n    fun `testing proper variables search in class with shadowing`() {\n        applyToCode(\"\"\"\n            class A {\n                var v = 0\n                fun foo() {\n                    v++\n                    var v = 1\n                    v++\n                }\n            }\n        \"\"\".trimIndent(), 0) { node, _ ->\n            if (node.elementType == KtFileElementType.INSTANCE) {\n                val vars = node.findAllVariablesWithUsages().mapKeys { it.key.text }\n                val keys = vars.keys\n                val var1 = keys.elementAt(0)\n                val var2 = keys.elementAt(1)\n                assertEquals(\"var v = 0\", var1)\n                assertEquals(1, vars[var1]?.size)\n                assertEquals(\"var v = 1\", var2)\n                assertEquals(1, vars[var2]?.size)\n            }\n        }\n    }\n\n    @Test\n    fun `testing proper variables search on global level`() {\n        applyToCode(\"\"\"\n            var v = 0\n            fun foo() {\n                v++\n                var v = 1\n                v++\n            }\n            class A {\n                fun foo() {\n                    v++\n                    var v = 2\n                    v++\n                }\n            }\n        \"\"\".trimIndent(), 0) { node, _ ->\n            if (node.elementType == KtFileElementType.INSTANCE) {\n                val vars = node.findAllVariablesWithUsages().mapKeys { it.key.text }\n                val keys = vars.keys\n                val var1 = keys.elementAt(0)\n                val var2 = keys.elementAt(1)\n                val var3 = keys.elementAt(2)\n                assertEquals(\"var v = 0\", var1)\n                assertEquals(2, vars[var1]?.size)\n                assertEquals(\"var v = 1\", var2)\n                assertEquals(1, vars[var2]?.size)\n                assertEquals(\"var v = 2\", var3)\n                assertEquals(1, vars[var3]?.size)\n            }\n        }\n    }\n\n    @Test\n    @Disabled\n    fun `testing proper variables search in companion object`() {\n        applyToCode(\"\"\"\n            var v = 0\n            class A {\n                companion object {\n                    var v = 1\n                }\n                fun foo() {\n                    v++\n                    var v = 2\n                    v++\n                }\n            }\n        \"\"\".trimIndent(), 0) { node, _ ->\n            if (node.elementType == KtFileElementType.INSTANCE) {\n                val vars = node.findAllVariablesWithUsages().mapKeys { it.key.text }\n                val keys = vars.keys\n                val var1 = keys.elementAt(0)\n                val var2 = keys.elementAt(1)\n                val var3 = keys.elementAt(1)\n                assertEquals(\"var v = 0\", var1)\n                assertEquals(0, vars[var1]?.size)\n                assertEquals(\"var v = 1\", var2)\n                assertEquals(1, vars[var2]?.size)\n                assertEquals(\"var v = 2\", var3)\n                assertEquals(1, vars[var3]?.size)\n            }\n        }\n    }\n\n    @Test\n    @Disabled\n    fun `testing proper variables search in companion object with less priority then property`() {\n        applyToCode(\"\"\"\n            var v = 0\n            class A {\n                companion object {\n                    var v = 1\n                }\n                fun foo() {\n                    v++\n                    var v = 2\n                    v++\n                }\n\n                var v = 3\n            }\n        \"\"\".trimIndent(), 0) { node, _ ->\n            if (node.elementType == KtFileElementType.INSTANCE) {\n                val vars = node.findAllVariablesWithUsages().mapKeys { it.key.text }\n                val keys = vars.keys\n                val var1 = keys.elementAt(0)\n                val var2 = keys.elementAt(1)\n                val var3 = keys.elementAt(2)\n                assertEquals(\"var v = 0\", var1)\n                assertEquals(0, vars[var1]?.size)\n                assertEquals(\"var v = 1\", var2)\n                assertEquals(0, vars[var2]?.size)\n                assertEquals(\"var v = 2\", var3)\n                assertEquals(1, vars[var3]?.size)\n                assertEquals(\"var v = 3\", var3)\n                assertEquals(1, vars[var3]?.size)\n            }\n        }\n    }\n\n    @Test\n    fun `testing proper variables search with while statement`() {\n        applyToCode(\"\"\"\n            class A {\n                fun foo() {\n                    var v = 1\n                    while(true) {\n                        v++\n                    }\n                    v++\n                }\n            }\n        \"\"\".trimIndent(), 0) { node, _ ->\n            if (node.elementType == KtFileElementType.INSTANCE) {\n                val vars = node.findAllVariablesWithUsages().mapKeys { it.key.text }\n                val keys = vars.keys\n                val var1 = keys.elementAt(0)\n                assertEquals(\"var v = 1\", var1)\n                assertEquals(2, vars[var1]?.size)\n            }\n        }\n    }\n\n    @Test\n    @Disabled\n    fun `testing proper variables search in class with the property in the end`() {\n        applyToCode(\"\"\"\n            class A {\n                fun foo() {\n                    v++\n                }\n\n                var v = 1\n            }\n        \"\"\".trimIndent(), 0) { node, _ ->\n            if (node.elementType == KtFileElementType.INSTANCE) {\n                val vars = node.findAllVariablesWithUsages().mapKeys { it.key.text }\n                val keys = vars.keys\n                val var1 = keys.elementAt(0)\n\n                assertEquals(\"var v = 1\", var1)\n                assertEquals(1, vars[var1]?.size)\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/test/kotlin/com/saveourtool/diktat/ruleset/utils/WarningsGenerationTest.kt",
    "content": "package com.saveourtool.diktat.ruleset.utils\n\nimport com.saveourtool.diktat.ruleset.constants.Warnings\nimport org.junit.jupiter.api.Test\n\nclass WarningsGenerationTest {\n    @Test\n    fun `checking that warnings has all proper fields filled`() {\n        Warnings.values().forEach { warn ->\n            assert(warn.ruleId.split(\".\").size == 3)\n        }\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/test/kotlin/com/saveourtool/diktat/util/DiktatRuleSetFactoryImplTest.kt",
    "content": "/**\n * Stub for diktat ruleset provide to be used in tests and other related utilities\n */\n\npackage com.saveourtool.diktat.util\n\nimport com.saveourtool.diktat.api.DiktatRuleSet\nimport com.saveourtool.diktat.common.config.rules.RulesConfig\nimport com.saveourtool.diktat.ruleset.config.DiktatRuleConfigYamlReader\nimport com.saveourtool.diktat.ruleset.rules.DiktatRule\nimport com.saveourtool.diktat.ruleset.rules.DiktatRuleSetFactoryImpl\nimport com.saveourtool.diktat.test.framework.util.filterContentMatches\n\nimport org.assertj.core.api.Assertions.assertThat\nimport org.junit.jupiter.api.Test\n\nimport java.nio.file.Path\nimport kotlin.io.path.ExperimentalPathApi\nimport kotlin.io.path.Path\nimport kotlin.io.path.isRegularFile\nimport kotlin.io.path.nameWithoutExtension\nimport kotlin.io.path.walk\n\nclass DiktatRuleSetFactoryImplTest {\n    @OptIn(ExperimentalPathApi::class)\n    @Suppress(\"UnsafeCallOnNullableType\")\n    @Test\n    fun `check DiktatRuleSetFactoryImpl contain all rules`() {\n        val path = \"${System.getProperty(\"user.dir\")}/src/main/kotlin/com/saveourtool/diktat/ruleset/rules\"\n        val fileNames = Path(path)\n            .walk()\n            .filter(Path::isRegularFile)\n            .filterContentMatches(linesToRead = 150, Regex(\"\"\":\\s*(?:Diktat)?Rule\\s*\\(\"\"\"))\n            .map(Path::nameWithoutExtension)\n            .filterNot { it in ignoredFileNames }\n            .toList()\n        val ruleNames = DiktatRuleSetFactoryImpl()\n            .invoke(emptyList())\n            .rules\n            .asSequence()\n            .map { it::class.simpleName }\n            .filterNotNull()\n            .filterNot { it in ignoredRuleNames }\n            .toList()\n        assertThat(fileNames).isNotEmpty\n        assertThat(ruleNames).isNotEmpty\n        assertThat(ruleNames.sorted()).containsExactlyElementsOf(fileNames.sorted())\n    }\n\n    companion object {\n        private val ignoredFileNames = listOf(\n            \"DiktatRule\",\n            \"OrderedRuleSet\",\n        )\n        private val ignoredRuleNames = listOf(\n            \"DummyWarning\",\n        )\n\n        /**\n         * Simple method to emulate [DiktatRuleSet] to inject `.yml` rule configuration and mock this part of code.\n         */\n        internal fun diktatRuleSetForTest(\n            ruleSupplier: (rulesConfigList: List<RulesConfig>) -> DiktatRule,\n            rulesConfigList: List<RulesConfig>?,\n        ): DiktatRuleSet = run {\n            rulesConfigList ?: Companion::class.java.classLoader.getResourceAsStream(\"diktat-analysis.yml\")\n                ?.let { DiktatRuleConfigYamlReader().invoke(it) }\n                .orEmpty()\n        }\n            .let(ruleSupplier)\n            .let {\n                DiktatRuleSet(listOf(it))\n            }\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/test/kotlin/com/saveourtool/diktat/util/DiktatRuleTest.kt",
    "content": "package com.saveourtool.diktat.util\n\nimport com.saveourtool.diktat.common.config.rules.DIKTAT_RULE_SET_ID\nimport com.saveourtool.diktat.common.config.rules.RulesConfig\nimport com.saveourtool.diktat.ruleset.constants.Warnings.BLANK_LINE_BETWEEN_PROPERTIES\nimport com.saveourtool.diktat.ruleset.constants.Warnings.WRONG_ORDER_IN_CLASS_LIKE_STRUCTURES\nimport com.saveourtool.diktat.ruleset.rules.chapter3.ClassLikeStructuresOrderRule\n\nimport com.saveourtool.diktat.api.DiktatError\nimport org.junit.jupiter.api.Test\n\nclass DiktatRuleTest : LintTestBase(::ClassLikeStructuresOrderRule) {\n    private val ruleId = \"$DIKTAT_RULE_SET_ID:${ClassLikeStructuresOrderRule.NAME_ID}\"\n    private val codeTemplate = \"\"\"\n        |class Example {\n        |   private val FOO = 42\n        |   private val log = LoggerFactory.getLogger(Example.javaClass)\n        |   // blank line between property\n        |   private val some = 2\n        |}\n    \"\"\".trimMargin()\n    private val rulesConfigAllDisabled = listOf(\n        RulesConfig(BLANK_LINE_BETWEEN_PROPERTIES.name, enabled = false),\n        RulesConfig(WRONG_ORDER_IN_CLASS_LIKE_STRUCTURES.name, enabled = false)\n    )\n    private val rulesConfigOneRuleIsEnabled = listOf(\n        RulesConfig(BLANK_LINE_BETWEEN_PROPERTIES.name, enabled = true),\n        RulesConfig(WRONG_ORDER_IN_CLASS_LIKE_STRUCTURES.name, enabled = false)\n    )\n\n    @Test\n    fun `check that if all inspections are disabled then rule won't run`() {\n        lintMethod(codeTemplate, rulesConfigList = rulesConfigAllDisabled)\n    }\n\n    @Test\n    fun `check that if one inspection is enabled then rule will run`() {\n        lintMethod(codeTemplate,\n            DiktatError(4, 4, ruleId, \"${BLANK_LINE_BETWEEN_PROPERTIES.warnText()} some\", true),\n            rulesConfigList = rulesConfigOneRuleIsEnabled\n        )\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/test/kotlin/com/saveourtool/diktat/util/FixTestBase.kt",
    "content": "package com.saveourtool.diktat.util\n\nimport com.saveourtool.diktat.api.DiktatCallback\nimport com.saveourtool.diktat.common.config.rules.RulesConfig\nimport com.saveourtool.diktat.ktlint.format\nimport com.saveourtool.diktat.ruleset.rules.DiktatRule\nimport com.saveourtool.diktat.test.framework.processing.ResourceReader\nimport com.saveourtool.diktat.test.framework.processing.TestComparatorUnit\nimport com.saveourtool.diktat.test.framework.processing.TestFileContent\nimport com.saveourtool.diktat.util.DiktatRuleSetFactoryImplTest.Companion.diktatRuleSetForTest\nimport io.github.oshai.kotlinlogging.KotlinLogging\nimport org.intellij.lang.annotations.Language\nimport java.nio.file.Path\nimport kotlin.io.path.bufferedWriter\nimport kotlin.io.path.createDirectories\nimport kotlin.io.path.div\n\n/**\n * Base class for FixTest\n */\nopen class FixTestBase(\n    resourceFilePath: String,\n    ruleSupplier: (rulesConfigList: List<RulesConfig>) -> DiktatRule,\n    defaultRulesConfigList: List<RulesConfig>? = null,\n    cb: DiktatCallback = defaultCallback,\n) {\n    /**\n     * testComparatorUnit\n     */\n    private val testComparatorUnitSupplier = { overrideRulesConfigList: List<RulesConfig>? ->\n        TestComparatorUnit(\n            resourceFilePath = resourceFilePath,\n            function = { testFile ->\n                format(\n                    ruleSetSupplier = { diktatRuleSetForTest(ruleSupplier, overrideRulesConfigList ?: defaultRulesConfigList) },\n                    file = testFile,\n                    cb = cb,\n                )\n            },\n        )\n    }\n\n    /**\n     * @param expectedPath path to file with expected result, relative to [resourceFilePath]\n     * @param testPath path to file with code that will be transformed by formatter, relative to [resourceFilePath]\n     * @param overrideRulesConfigList optional override to [defaultRulesConfigList]\n     * @param overrideResourceReader function to override [ResourceReader] to read resource content.\n     * @see fixAndCompareContent\n     */\n    protected fun fixAndCompare(\n        expectedPath: String,\n        testPath: String,\n        overrideRulesConfigList: List<RulesConfig>? = null,\n        overrideResourceReader: (ResourceReader) -> ResourceReader = { it },\n    ) {\n        val testComparatorUnit = testComparatorUnitSupplier(overrideRulesConfigList)\n        val result = testComparatorUnit\n            .compareFilesFromResources(expectedPath, testPath, overrideResourceReader)\n        result.assertSuccessful()\n    }\n\n    /**\n     * Unlike [fixAndCompare], this method doesn't perform any assertions.\n     *\n     * @param actualContent the original file content (may well be modified as\n     *   fixes are applied).\n     * @param expectedContent the content the file is expected to have after the\n     *   fixes are applied.\n     * @param tempDir the temporary directory (usually injected by _JUnit_).\n     * @param overrideRulesConfigList an optional override for [rulesConfigList]\n     *   (the class-wide configuration).\n     * @return the result of file content comparison.\n     * @see fixAndCompare\n     */\n    @Suppress(\"FUNCTION_BOOLEAN_PREFIX\")\n    protected fun fixAndCompareContent(\n        @Language(\"kotlin\") actualContent: String,\n        @Language(\"kotlin\") expectedContent: String = actualContent,\n        tempDir: Path,\n        subFolder: String? = null,\n        overrideRulesConfigList: List<RulesConfig>? = null\n    ): TestFileContent {\n        val folder = subFolder?.let { tempDir / it }?.also { it.createDirectories() } ?: tempDir\n        val actual = folder / \"actual.kt\"\n        actual.bufferedWriter().use { out ->\n            out.write(actualContent)\n        }\n\n        val expected = folder / \"expected.kt\"\n        expected.bufferedWriter().use { out ->\n            out.write(expectedContent)\n        }\n\n        val testComparatorUnit = testComparatorUnitSupplier(overrideRulesConfigList)\n        return testComparatorUnit\n            .compareFilesFromFileSystem(expected, actual)\n    }\n\n    companion object {\n        private val log = KotlinLogging.logger { }\n\n        private val defaultCallback = DiktatCallback { error, _ ->\n            log.warn { \"Received linting error: $error\" }\n        }\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/test/kotlin/com/saveourtool/diktat/util/LintTestBase.kt",
    "content": "package com.saveourtool.diktat.util\n\nimport com.saveourtool.diktat.api.DiktatCallback\nimport com.saveourtool.diktat.common.config.rules.RulesConfig\nimport com.saveourtool.diktat.ktlint.check\nimport com.saveourtool.diktat.ruleset.rules.DiktatRule\nimport com.saveourtool.diktat.util.DiktatRuleSetFactoryImplTest.Companion.diktatRuleSetForTest\nimport com.saveourtool.diktat.api.DiktatError\nimport org.assertj.core.api.Assertions.assertThat\nimport org.intellij.lang.annotations.Language\nimport java.nio.file.Path\nimport kotlin.io.path.createDirectories\nimport kotlin.io.path.readText\nimport kotlin.io.path.writeText\n\n/**\n * Base class for testing rules without fixing code.\n * @property ruleSupplier mapping of list of [RulesConfig] into a [DiktatRule]\n * @property rulesConfigList optional custom rules config\n */\nopen class LintTestBase(private val ruleSupplier: (rulesConfigList: List<RulesConfig>) -> DiktatRule,\n                        private val rulesConfigList: List<RulesConfig>? = null) {\n    /**\n     * Perform linting of [code], collect errors and compare with [expectedLintErrors]\n     *\n     * @param code code to check\n     * @param expectedLintErrors expected errors\n     * @param rulesConfigList optional override for `this.rulesConfigList`\n     * @see lintResult\n     */\n    fun lintMethod(@Language(\"kotlin\") code: String,\n                   vararg expectedLintErrors: DiktatError,\n                   rulesConfigList: List<RulesConfig>? = null,\n    ) = doAssert(\n        actualLintErrors = lintResult(code, rulesConfigList),\n        description = \"lint result for \\\"$code\\\"\",\n        expectedLintErrors = expectedLintErrors\n    )\n\n    /**\n     * Perform linting of [code] by creating a file in [tempDir] with [fileName], collect errors and compare with [expectedLintErrors]\n     *\n     * @param code code to check\n     * @param tempDir a path to temporary folder\n     * @param fileName relative path to file which needs to be checked\n     * @param expectedLintErrors expected errors\n     * @param rulesConfigList optional override for `this.rulesConfigList`\n     * @see lintResult\n     */\n    fun lintMethodWithFile(\n        @Language(\"kotlin\") code: String,\n        tempDir: Path,\n        fileName: String,\n        vararg expectedLintErrors: DiktatError,\n        rulesConfigList: List<RulesConfig>? = null,\n    ) {\n        val file = tempDir.resolve(fileName).also {\n            it.parent.createDirectories()\n            it.writeText(code)\n        }\n        lintMethodWithFile(\n            file = file,\n            expectedLintErrors = expectedLintErrors,\n            rulesConfigList = rulesConfigList,\n        )\n    }\n\n    /**\n     * Perform linting of [file], collect errors and compare with [expectedLintErrors]\n     *\n     * @param file a path to file to check\n     * @param expectedLintErrors expected errors\n     * @param rulesConfigList optional override for `this.rulesConfigList`\n     * @see lintResult\n     */\n    fun lintMethodWithFile(\n        file: Path,\n        vararg expectedLintErrors: DiktatError,\n        rulesConfigList: List<RulesConfig>? = null,\n    ) = doAssert(\n        actualLintErrors = lintResult(file, rulesConfigList),\n        description = \"lint result for \\\"${file.readText()}\\\"\",\n        expectedLintErrors = expectedLintErrors\n    )\n\n    private fun doAssert(\n        actualLintErrors: List<DiktatError>,\n        description: String,\n        vararg expectedLintErrors: DiktatError,\n    ) {\n        when {\n            expectedLintErrors.size == 1 && actualLintErrors.size == 1 -> {\n                val actual = actualLintErrors[0]\n                val expected = expectedLintErrors[0]\n\n                assertThat(actual)\n                    .describedAs(description)\n                    .isEqualTo(expected)\n                assertThat(actual.canBeAutoCorrected)\n                    .describedAs(\"canBeAutoCorrected\")\n                    .isEqualTo(expected.canBeAutoCorrected)\n            }\n\n            else -> assertThat(actualLintErrors)\n                .describedAs(description)\n                .apply {\n                    when {\n                        expectedLintErrors.isEmpty() -> isEmpty()\n                        else -> containsExactly(*expectedLintErrors)\n                    }\n                }\n        }\n    }\n\n    /**\n     * Lints the [file] and returns the errors collected, but (unlike\n     * [lintMethodWithFile]) doesn't make any assertions.\n     *\n     * @param file the file to check.\n     * @param rulesConfigList an optional override for `this.rulesConfigList`.\n     * @return the list of lint errors.\n     * @see lintMethodWithFile\n     */\n    private fun lintResult(\n        file: Path,\n        rulesConfigList: List<RulesConfig>? = null,\n    ): List<DiktatError> {\n        val lintErrors: MutableList<DiktatError> = mutableListOf()\n\n        check(\n            ruleSetSupplier = { rulesConfigList.toDiktatRuleSet() },\n            file = file,\n            cb = lintErrors.collector(),\n        )\n\n        return lintErrors\n    }\n\n    /**\n     * Lints the [code] and returns the errors collected, but (unlike\n     * [lintMethodWithFile]) doesn't make any assertions.\n     *\n     * @param code the code to check.\n     * @param rulesConfigList an optional override for `this.rulesConfigList`.\n     * @return the list of lint errors.\n     * @see lintMethodWithFile\n     */\n    protected fun lintResult(\n        @Language(\"kotlin\") code: String,\n        rulesConfigList: List<RulesConfig>? = null,\n    ): List<DiktatError> {\n        val lintErrors: MutableList<DiktatError> = mutableListOf()\n\n        check(\n            ruleSetSupplier = { rulesConfigList.toDiktatRuleSet() },\n            text = code,\n            cb = lintErrors.collector(),\n        )\n\n        return lintErrors\n    }\n\n    private fun List<RulesConfig>?.toDiktatRuleSet() = diktatRuleSetForTest(ruleSupplier, this ?: rulesConfigList)\n\n    companion object {\n        private fun MutableList<DiktatError>.collector(): DiktatCallback = DiktatCallback { error, _ ->\n            this += error\n        }\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/test/kotlin/com/saveourtool/diktat/util/SuppressingTest.kt",
    "content": "package com.saveourtool.diktat.util\n\nimport com.saveourtool.diktat.common.config.rules.DIKTAT_RULE_SET_ID\nimport com.saveourtool.diktat.common.config.rules.RulesConfig\nimport com.saveourtool.diktat.ruleset.constants.Warnings.IDENTIFIER_LENGTH\nimport com.saveourtool.diktat.ruleset.rules.chapter1.IdentifierNaming\n\nimport com.saveourtool.diktat.api.DiktatError\nimport org.junit.jupiter.api.Test\n\nclass SuppressingTest : LintTestBase(::IdentifierNaming) {\n    private val ruleId: String = \"$DIKTAT_RULE_SET_ID:${IdentifierNaming.NAME_ID}\"\n    private val rulesConfigBooleanFunctions: List<RulesConfig> = listOf(\n        RulesConfig(IDENTIFIER_LENGTH.name, true, emptyMap(), setOf(\"MySuperSuppress\"))\n    )\n\n    @Test\n    fun `checking that suppression with ignoredAnnotation works`() {\n        val code =\n            \"\"\"\n                @MySuperSuppress()\n                fun foo() {\n                    val a = 1\n                }\n            \"\"\".trimIndent()\n        lintMethod(code, rulesConfigList = rulesConfigBooleanFunctions)\n    }\n\n    @Test\n    fun `checking that suppression with ignore everything works`() {\n        val code =\n            \"\"\"\n                @Suppress(\"diktat\")\n                fun foo() {\n                    val a = 1\n                }\n            \"\"\".trimIndent()\n        lintMethod(code)\n    }\n\n    @Test\n    fun `checking that suppression with a targeted inspection name works`() {\n        val code =\n            \"\"\"\n                @Suppress(\"IDENTIFIER_LENGTH\")\n                fun foo() {\n                    val a = 1\n                }\n            \"\"\".trimIndent()\n        lintMethod(code)\n    }\n\n    @Test\n    fun `negative scenario for other annotation`() {\n        val code =\n            \"\"\"\n                @MySuperSuppress111()\n                fun foo() {\n                    val a = 1\n                }\n            \"\"\".trimIndent()\n        lintMethod(\n            code,\n            DiktatError(3,\n                9,\n                ruleId,\n                \"[IDENTIFIER_LENGTH] identifier's length is incorrect, it\" +\n                        \" should be in range of [2, 64] symbols: a\", false),\n            rulesConfigList = rulesConfigBooleanFunctions,\n        )\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/test/kotlin/com/saveourtool/diktat/util/TestUtils.kt",
    "content": "/**\n * Utility classes and methods for tests\n */\n\npackage com.saveourtool.diktat.util\n\nimport com.saveourtool.diktat.api.DiktatErrorEmitter\nimport com.saveourtool.diktat.api.DiktatRule\nimport com.saveourtool.diktat.api.DiktatRuleSet\nimport com.saveourtool.diktat.ktlint.check\n\nimport org.assertj.core.api.Assertions.assertThat\nimport org.assertj.core.api.Assertions.fail\nimport org.intellij.lang.annotations.Language\nimport org.jetbrains.kotlin.com.intellij.lang.ASTNode\n\nimport java.io.Reader\nimport java.util.concurrent.atomic.AtomicInteger\nimport kotlin.contracts.ExperimentalContracts\nimport kotlin.contracts.InvocationKind.EXACTLY_ONCE\nimport kotlin.contracts.contract\n\ninternal const val TEST_FILE_NAME = \"TestFileName.kt\"\n\n/**\n * Casts a nullable value to a non-`null` one, similarly to the `!!`\n * operator.\n *\n * @param lazyFailureMessage the message to evaluate in case of a failure.\n * @return a non-`null` value.\n */\n@OptIn(ExperimentalContracts::class)\ninternal fun <T : Any> T?.assertNotNull(lazyFailureMessage: () -> String = { \"Expecting actual not to be null\" }): T {\n    contract {\n        returns() implies (this@assertNotNull != null)\n    }\n\n    return this ?: fail(lazyFailureMessage())\n}\n\n/**\n * This utility function lets you run arbitrary code on every node of given [code].\n * It also provides you with counter which can be incremented inside [applyToNode] and then will be compared to [expectedAsserts].\n * This allows you to keep track of how many assertions have actually been run on your code during tests.\n *\n * @param code\n * @param expectedAsserts Number of expected times of assert invocation\n * @param applyToNode Function to be called on each AST node, should increment counter if assert is called\n */\n@Suppress(\"TYPE_ALIAS\")\ninternal fun applyToCode(@Language(\"kotlin\") code: String,\n                         expectedAsserts: Int,\n                         applyToNode: (node: ASTNode, counter: AtomicInteger) -> Unit\n) {\n    val counter = AtomicInteger(0)\n    check(\n        ruleSetSupplier = {\n            DiktatRuleSet(listOf(object : DiktatRule {\n                override val id: String\n                    get() = \"astnode-utils-test\"\n                override fun invoke(node: ASTNode, autoCorrect: Boolean, emitter: DiktatErrorEmitter) {\n                    applyToNode(node, counter)\n                }\n            }))\n        },\n        text = code,\n    )\n    assertThat(counter.get())\n        .`as`(\"Number of expected asserts\")\n        .isEqualTo(expectedAsserts)\n}\n"
  },
  {
    "path": "diktat-rules/src/test/resources/log4j2.properties",
    "content": "rootLogger.level = info\nrootLogger.appenderRef.stdout.ref = STDOUT\n\nappender.stdout.type = Console\nappender.stdout.name = STDOUT\nappender.stdout.target = SYSTEM_OUT\nappender.stdout.layout.type = PatternLayout\nappender.stdout.layout.pattern = [%-5p] %d{yyyy-MM-dd HH:mm:ss} %m%n\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/chapter6/abstract_classes/ShouldReplaceAbstractKeywordExpected.kt",
    "content": "package test.paragraph6.abstract_classes\n\nactual open class CoroutineTest actual constructor() {\n    actual fun <T> runTest(block: suspend CoroutineScope.() -> T) {\n        runBlocking {\n            block()\n        }\n    }\n}\n\nopen class Some() {\n    fun some(){}\n\n    fun another(){}\n\n    @SomeAnnotation @Another open inner class Any {\n        fun func(){}\n    }\n\n    inner open class Second {\n        fun someFunc(){}\n    }\n}\n\nabstract class Another {\n    abstract fun absFunc()\n\n    fun someFunc(){}\n}\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/chapter6/abstract_classes/ShouldReplaceAbstractKeywordTest.kt",
    "content": "package test.paragraph6.abstract_classes\n\nactual abstract class CoroutineTest actual constructor() {\n    actual fun <T> runTest(block: suspend CoroutineScope.() -> T) {\n        runBlocking {\n            block()\n        }\n    }\n}\n\nabstract class Some() {\n    fun some(){}\n\n    fun another(){}\n\n    @SomeAnnotation @Another abstract inner class Any {\n        fun func(){}\n    }\n\n    inner abstract class Second {\n        fun someFunc(){}\n    }\n}\n\nabstract class Another {\n    abstract fun absFunc()\n\n    fun someFunc(){}\n}\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/chapter6/classes/AssignmentWithLocalPropertyExpected.kt",
    "content": "package test.chapter6.classes\n\nclass Foo (a: Int){\n    val a: Int\n\n    init {\n    val f = F(a)\nthis.a = f.foo()\n}\n}"
  },
  {
    "path": "diktat-rules/src/test/resources/test/chapter6/classes/AssignmentWithLocalPropertyTest.kt",
    "content": "package test.chapter6.classes\n\nclass Foo {\n    val a: Int\n\n    constructor(a: Int) {\n        val f = F(a)\n        this.a = f.foo()\n    }\n}"
  },
  {
    "path": "diktat-rules/src/test/resources/test/chapter6/classes/ConstructorShouldKeepExpressionsOrderExpected.kt",
    "content": "package test.chapter6.classes\n\nclass Test (){\n    init {\n    str = \"ABC\"\nprintln(str)\nstr = str.reversed()\nprintln(str)\n}\n    var str: String\n}"
  },
  {
    "path": "diktat-rules/src/test/resources/test/chapter6/classes/ConstructorShouldKeepExpressionsOrderTest.kt",
    "content": "package test.chapter6.classes\n\nclass Test {\n    constructor() {\n        str = \"ABC\"\n        println(str)\n        str = str.reversed()\n        println(str)\n    }\n    var str: String\n}"
  },
  {
    "path": "diktat-rules/src/test/resources/test/chapter6/classes/ConstructorWithCommentsExpected.kt",
    "content": "package test.chapter6.classes\n\nclass Test (){\ninit {\n    println(\"A\")\n// import is a weak keyword imported\nprintln(\"B\")\n/* import is a weak keyword */\nprintln(\"C\")\n/**\n* import is a weak keyword\n*/\nprintln(\"D\")\n}\n}\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/chapter6/classes/ConstructorWithCommentsTest.kt",
    "content": "package test.chapter6.classes\n\nclass Test {\nconstructor() {\nprintln(\"A\")\n// import is a weak keyword imported\nprintln(\"B\")\n/* import is a weak keyword */\nprintln(\"C\")\n/**\n* import is a weak keyword\n*/\nprintln(\"D\")\n}\n}\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/chapter6/classes/ConstructorWithComplexAssignmentsExpected.kt",
    "content": "package test.chapter6.classes\n\nclass A {\n    var b: String = \"\"\n    constructor(a: Int) {\n        // help\n        b = a.toString()\n    }\n    fun foo1() {\n\n    }\n    // ssss\n    fun foo() {\n\n    }\n}"
  },
  {
    "path": "diktat-rules/src/test/resources/test/chapter6/classes/ConstructorWithComplexAssignmentsTest.kt",
    "content": "package test.chapter6.classes\n\nclass A {\n    var b: String = \"\"\n    constructor(a: Int) {\n        // help\n        b = a.toString()\n    }\n    fun foo1() {\n\n    }\n    // ssss\n    fun foo() {\n\n    }\n}"
  },
  {
    "path": "diktat-rules/src/test/resources/test/chapter6/classes/ConstructorWithCustomAssignmentsExpected.kt",
    "content": "package test.chapter6.classes\n\nclass Test (a: Int){\n    var a: Int\n\n    init {\n    this.a = a + 42\n}\n}"
  },
  {
    "path": "diktat-rules/src/test/resources/test/chapter6/classes/ConstructorWithCustomAssignmentsTest.kt",
    "content": "package test.chapter6.classes\n\nclass Test {\n    var a: Int\n\n    constructor(a: Int) {\n        this.a = a + 42\n    }\n}"
  },
  {
    "path": "diktat-rules/src/test/resources/test/chapter6/classes/ConstructorWithInitExpected.kt",
    "content": "package test.chapter6.classes\n\nclass Test (var a: Int){\n\ninit {\n    println(\"Lorem ipsum\")\nfoo()\n}\n}"
  },
  {
    "path": "diktat-rules/src/test/resources/test/chapter6/classes/ConstructorWithInitTest.kt",
    "content": "package test.chapter6.classes\n\nclass Test {\nvar a: Int\n\nconstructor(a: Int) {\n    println(\"Lorem ipsum\")\n    foo()\n    this.a = a\n}\n}"
  },
  {
    "path": "diktat-rules/src/test/resources/test/chapter6/classes/ConstructorWithModifiersExpected.kt",
    "content": "package test.chapter6.classes\n\nclass Test @Annotation private constructor (var a: Int){\n}"
  },
  {
    "path": "diktat-rules/src/test/resources/test/chapter6/classes/ConstructorWithModifiersTest.kt",
    "content": "package test.chapter6.classes\n\nclass Test {\nvar a: Int\n\n@Annotation private constructor(a: Int) {\n    this.a = a\n}\n}"
  },
  {
    "path": "diktat-rules/src/test/resources/test/chapter6/classes/SimpleConstructorExpected.kt",
    "content": "package test.chapter6.classes\n\nclass Test (var a: Int){\n}\n\nclass Test (var a: Int){\n}\n\nclass Test (var a: Int){\n\ninit {\n    var a = 14\n}\n}"
  },
  {
    "path": "diktat-rules/src/test/resources/test/chapter6/classes/SimpleConstructorTest.kt",
    "content": "package test.chapter6.classes\n\nclass Test {\nvar a: Int\n\nconstructor(a: Int) {\n    this.a = a\n}\n}\n\nclass Test {\nvar a: Int\n\nconstructor(_a: Int) {\n    a = _a\n}\n}\n\nclass Test {\nvar a: Int\n\nconstructor(_a: Int) {\n    var a = 14\n    a = _a\n    this.a = _a\n}\n}"
  },
  {
    "path": "diktat-rules/src/test/resources/test/chapter6/compact_initialization/ApplyOnStatementsWithThisKeywordExpected.kt",
    "content": "fun String.createPluginConfig() {\n    val pluginConfig = TomlDecoder.decode<T>(\n        serializer(),\n        fakeFileNode,\n        DecoderConf()\n    ).apply {\n    prop1 = property1\n    // comment2\n    prop2 = property2}\n    pluginConfig.configLocation = this.toPath()\n    // comment1\n    pluginConfig.configLocation2 = this.toPath()\n}\n\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/chapter6/compact_initialization/ApplyOnStatementsWithThisKeywordTest.kt",
    "content": "fun String.createPluginConfig() {\n    val pluginConfig = TomlDecoder.decode<T>(\n        serializer(),\n        fakeFileNode,\n        DecoderConf()\n    )\n    pluginConfig.configLocation = this.toPath()\n    pluginConfig.prop1 = property1\n    // comment1\n    pluginConfig.configLocation2 = this.toPath()\n    // comment2\n    pluginConfig.prop2 = property2\n}\n\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/chapter6/compact_initialization/ApplyWithValueArgumentExpected.kt",
    "content": "fun main() {\nval httpClient = HttpClient(\"myConnection\").apply {\n    setDefaultUrl(this)\nport = \"8080\"\ntimeout = 100\n}\nhttpClient.doRequest()\n}\n\nfun setDefaultUrl(httpClient: HttpClient) {\n    httpClient.url = \"http://example.com\"\n}\n\nfun foo() {\n    val diktatExtension = project.extensions.create(DIKTAT_EXTENSION, DiktatExtension::class.java).apply {\n    inputs = project.fileTree(\"src\").apply {\n        include(\"**/*.kt\")\n    }\n    reporter = PlainReporter(System.out)}\n}"
  },
  {
    "path": "diktat-rules/src/test/resources/test/chapter6/compact_initialization/ApplyWithValueArgumentTest.kt",
    "content": "fun main() {\nval httpClient = HttpClient(\"myConnection\").apply(::setDefaultUrl)\nhttpClient.port = \"8080\"\nhttpClient.timeout = 100\nhttpClient.doRequest()\n}\n\nfun setDefaultUrl(httpClient: HttpClient) {\n    httpClient.url = \"http://example.com\"\n}\n\nfun foo() {\n    val diktatExtension = project.extensions.create(DIKTAT_EXTENSION, DiktatExtension::class.java)\n    diktatExtension.inputs = project.fileTree(\"src\").apply {\n        include(\"**/*.kt\")\n    }\n    diktatExtension.reporter = PlainReporter(System.out)\n}"
  },
  {
    "path": "diktat-rules/src/test/resources/test/chapter6/compact_initialization/ExampleWithCommentsExpected.kt",
    "content": "fun main() {\nval httpClient = HttpClient(\"myConnection\").apply {\n// assigning URL\nurl = \"http://example.com\"\n\n// setting port to 8080\nport = \"8080\"\n/* we set timeout\nin case it times out\n*/\ntimeout = 100}\n// finally, we can make request\nhttpClient.doRequest()\n}"
  },
  {
    "path": "diktat-rules/src/test/resources/test/chapter6/compact_initialization/ExampleWithCommentsTest.kt",
    "content": "fun main() {\nval httpClient = HttpClient(\"myConnection\")\n// assigning URL\nhttpClient.url = \"http://example.com\"\n\n// setting port to 8080\nhttpClient.port = \"8080\"\n/* we set timeout\nin case it times out\n*/\nhttpClient.timeout = 100\n// finally, we can make request\nhttpClient.doRequest()\n}"
  },
  {
    "path": "diktat-rules/src/test/resources/test/chapter6/compact_initialization/ParenthesizedReceiverExpected.kt",
    "content": "fun `translate text`() {\n    val res = translateText(text = \"dummy\")\n    (res is TranslationsSuccess) shouldBe true\n    val translationsSuccess = (res as TranslationsSuccess).apply {\n    translations = 1}\n}\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/chapter6/compact_initialization/ParenthesizedReceiverTest.kt",
    "content": "fun `translate text`() {\n    val res = translateText(text = \"dummy\")\n    (res is TranslationsSuccess) shouldBe true\n    val translationsSuccess = res as TranslationsSuccess\n    translationsSuccess.translations = 1\n}\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/chapter6/compact_initialization/SimpleExampleExpected.kt",
    "content": "fun main() {\nval httpClient = HttpClient(\"myConnection\").apply {\nurl = \"http://example.com\"\nport = \"8080\"\ntimeout = 100}\nhttpClient.doRequest()\n}"
  },
  {
    "path": "diktat-rules/src/test/resources/test/chapter6/compact_initialization/SimpleExampleTest.kt",
    "content": "fun main() {\nval httpClient = HttpClient(\"myConnection\")\nhttpClient.url = \"http://example.com\"\nhttpClient.port = \"8080\"\nhttpClient.timeout = 100\nhttpClient.doRequest()\n}"
  },
  {
    "path": "diktat-rules/src/test/resources/test/chapter6/compact_initialization/StatementUseFieldMultipleTimesExpected.kt",
    "content": "fun foo() {\n    val execution = Execution().apply {\n    id = executionService.saveExecution(this)}\n    return execution.id!!\n}\n\nfun foo() {\n    val execution = Execution().apply {\n    id = executionService.saveExecution(this)\n    sdk = this.defaultSdk(this)\n    id2 = this.id + shift\n    name = this.execution(this)}\n    return execution.id!!\n}\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/chapter6/compact_initialization/StatementUseFieldMultipleTimesTest.kt",
    "content": "fun foo() {\n    val execution = Execution()\n    execution.id = executionService.saveExecution(execution)\n    return execution.id!!\n}\n\nfun foo() {\n    val execution = Execution()\n    execution.id = executionService.saveExecution(execution)\n    execution.sdk = execution.defaultSdk(execution)\n    execution.id2 = execution.id + shift\n    execution.name = execution.execution(execution)\n    return execution.id!!\n}\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/chapter6/init_blocks/InitBlockWithAssignmentsExpected.kt",
    "content": "package test.chapter6.init_blocks\n\nclass A(baseUrl: String) {\n    private val customUrl: String = \"$baseUrl/myUrl\"\n\n}"
  },
  {
    "path": "diktat-rules/src/test/resources/test/chapter6/init_blocks/InitBlockWithAssignmentsTest.kt",
    "content": "package test.chapter6.init_blocks\n\nclass A(baseUrl: String) {\n    private val customUrl: String\ninit {\n        customUrl = \"$baseUrl/myUrl\"\n    }\n}"
  },
  {
    "path": "diktat-rules/src/test/resources/test/chapter6/init_blocks/InitBlocksExpected.kt",
    "content": "package test.chapter6.init_blocks\n\nclass Example {\n    init { println(\"Lorem ipsum\")\nprintln(\"Dolor sit amet\") }\n\n    val foo = 0\n\n    }"
  },
  {
    "path": "diktat-rules/src/test/resources/test/chapter6/init_blocks/InitBlocksTest.kt",
    "content": "package test.chapter6.init_blocks\n\nclass Example {\n    init { println(\"Lorem ipsum\") }\n\n    val foo = 0\n\n    init { println(\"Dolor sit amet\") }\n}"
  },
  {
    "path": "diktat-rules/src/test/resources/test/chapter6/init_blocks/InitBlocksWithAssignmentsExpected.kt",
    "content": "package test.chapter6.init_blocks\n\nclass A(baseUrl: String) {\n    private val customUrl: String = \"$baseUrl/myUrl\"\n    init {\n        println(\"Lorem ipsum\")\nprintln(\"Dolor sit amet\")\n    }\n\n    }"
  },
  {
    "path": "diktat-rules/src/test/resources/test/chapter6/init_blocks/InitBlocksWithAssignmentsTest.kt",
    "content": "package test.chapter6.init_blocks\n\nclass A(baseUrl: String) {\n    private val customUrl: String\n    init {\n        customUrl = \"$baseUrl/myUrl\"\n        println(\"Lorem ipsum\")\n    }\n\n    init { println(\"Dolor sit amet\") }\n}"
  },
  {
    "path": "diktat-rules/src/test/resources/test/chapter6/lastIndex_change/IncorrectUseLengthMinusOneExpected.kt",
    "content": "package test.chapter6.lastIndex_change\n\nfun main(args: Array<String>) {\n\n    val str = \"ASDFG\"\n    val A = str.lastIndex\n    val B = str.lastIndex\n\n}"
  },
  {
    "path": "diktat-rules/src/test/resources/test/chapter6/lastIndex_change/IncorrectUseLengthMinusOneTest.kt",
    "content": "package test.chapter6.lastIndex_change\n\nfun main(args: Array<String>) {\n\n    val str = \"ASDFG\"\n    val A = str.length - 1\n    val B = str.length - 1\n\n}"
  },
  {
    "path": "diktat-rules/src/test/resources/test/chapter6/lastIndex_change/UseAnyWhiteSpacesExpected.kt",
    "content": "package test.chapter6.lastIndex_change\n\nfun main(args: Array<String>) {\n    val str = \"ASDFG\"\n    val A = str.lastIndex\n    val B = str.lastIndex\n    val C = str.lastIndex\n    val D = str.lastIndex\n    val F = str.lastIndex\n    val E = str[str.lastIndex]\n    val G = str[str.lastIndex ]\n}"
  },
  {
    "path": "diktat-rules/src/test/resources/test/chapter6/lastIndex_change/UseAnyWhiteSpacesTest.kt",
    "content": "package test.chapter6.lastIndex_change\n\nfun main(args: Array<String>) {\n    val str = \"ASDFG\"\n    val A = str.length    -         1\n    val B = str.length-1\n    val C = str.length    -1\n    val D = str.length-     1\n    val F = str.length - 1\n    val E = str[str.length - 1]\n    val G = str[str.length  -  1 ]\n}"
  },
  {
    "path": "diktat-rules/src/test/resources/test/chapter6/primary_constructor/EmptyPCExpected.kt",
    "content": "package test.chapter6.primary_constructor\n\nclass Test {\n    var a: Int = 0\n    var b: Int = 0\n}\n\nclass Test {\n    var a  = \"Property\"\n\n    init {\n        println(\"some init\")\n    }\n\n    constructor(a: String): this() {\n        this.a = a\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/chapter6/primary_constructor/EmptyPCTest.kt",
    "content": "package test.chapter6.primary_constructor\n\nclass Test() {\n    var a: Int = 0\n    var b: Int = 0\n}\n\nclass Test() {\n    var a  = \"Property\"\n\n    init {\n        println(\"some init\")\n    }\n\n    constructor(a: String): this() {\n        this.a = a\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/chapter6/properties/TrivialPropertyAccessorsExpected.kt",
    "content": "package test.chapter6.properties\n\nclass Some {\n    var prop: Int = 0\n\n    val prop2: Int = 0\n\n    var propNotChange: Int = 7\n        get() { return someCoolLogic(field) }\n        set(value) { anotherCoolLogic(value) }\n\n    var testName: String? = null\n        private set\n\n    val x = 0\n}"
  },
  {
    "path": "diktat-rules/src/test/resources/test/chapter6/properties/TrivialPropertyAccessorsTest.kt",
    "content": "package test.chapter6.properties\n\nclass Some {\n    var prop: Int = 0\n        get() = field\n        set(value) { field = value }\n\n    val prop2: Int = 0\n        get() { return field }\n\n    var propNotChange: Int = 7\n        get() { return someCoolLogic(field) }\n        set(value) { anotherCoolLogic(value) }\n\n    var testName: String? = null\n        private set\n\n    val x = 0\n        get\n}"
  },
  {
    "path": "diktat-rules/src/test/resources/test/chapter6/script/SimpleRunInScriptExpected.kts",
    "content": "\nrun {\n println(\"hello world!\")\n}\n\nfun foo() {\n    println()\n}\n\nval q = Config()\n\nrun {\n    println(\"a\")\n}\n\nalso {\n    println(\"a\")\n}\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/chapter6/script/SimpleRunInScriptTest.kts",
    "content": "\nprintln(\"hello world!\")\n\nfun foo() {\n    println()\n}\n\nval q = Config()\n\nrun {\n    println(\"a\")\n}\n\nalso {\n    println(\"a\")\n}\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/chapter6/stateless_classes/StatelessClassExpected.kt",
    "content": "package test.chapter6.stateless_classes\n\ninterface I {\n    fun foo()\n}\n\nobject O: I {\n    override fun foo() {}\n}\n\n/**\n * Some KDOC\n */\nobject A: I {\n    override fun foo() {}\n}\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/chapter6/stateless_classes/StatelessClassTest.kt",
    "content": "package test.chapter6.stateless_classes\n\ninterface I {\n    fun foo()\n}\n\nclass O: I {\n    override fun foo() {}\n}\n\n/**\n * Some KDOC\n */\nclass A: I {\n    override fun foo() {}\n}\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph1/naming/class_/IncorrectClassNameExpected.kt",
    "content": "package com.saveourtool.diktat.test.paragraph1.naming.class_\n\nclass PaScalCase1 {}\nclass PascalCase2 {}\nclass PascalCase3 {}\nclass PascalCase4 {}\nclass Pascalcase5 {}\nclass Pascalcase6 {}\nclass PascAlCase7 {}\nclass PascaLcase8 {}\nclass PascAlCase9 {}\nclass PascAlCase10 {}\nclass PascAlCase11 {}\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph1/naming/class_/IncorrectClassNameTest.kt",
    "content": "package com.saveourtool.diktat.test.paragraph1.naming.class_\n\nclass PaScalCase1 {}\nclass Pascal_Case2 {}\nclass Pascal_case3 {}\nclass Pascal_Case4 {}\nclass Pascalcase5 {}\nclass Pascalcase6 {}\nclass PascAl_Case7 {}\nclass PascaL_Case8 {}\nclass PascAL_Case9 {}\nclass _PascAL_Case10 {}\nclass PascAL_Case11_ {}\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph1/naming/enum_/EnumValuePascalCaseExpected.kt",
    "content": "package com.saveourtool.diktat.test.resources.test.paragraph1.naming.enum_\n\nenum class EnumValuePascalCaseTest {\n    PaScSalL,\n    PascAslF,\n    StartPsaaaDfe,\n    NameMyaSayR,\n    NameMyaSayR\n}\n\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph1/naming/enum_/EnumValuePascalCaseTest.kt",
    "content": "package com.saveourtool.diktat.test.resources.test.paragraph1.naming.enum_\n\nenum class EnumValuePascalCaseTest {\n    paSC_SAl_l,\n    PascAsl_f,\n    START_PSaaa_DFE,\n    _NAme_MYa_sayR,\n    NAme_MYa_sayR_\n}\n\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph1/naming/enum_/EnumValueSnakeCaseExpected.kt",
    "content": "package com.saveourtool.diktat.test.resources.test.paragraph1.naming.enum_\n\nenum class EnumValueSnakeCaseTest {\n    PA_SC_SAL_L,\n    PASC_ASL_F,\n    START_PSAAA_DFE,\n    NAME_MYA_SAY_R,\n    NAME_MYA_SAY_R_\n}\n\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph1/naming/enum_/EnumValueSnakeCaseTest.kt",
    "content": "package com.saveourtool.diktat.test.resources.test.paragraph1.naming.enum_\n\nenum class EnumValueSnakeCaseTest {\n    paSC_SAl_l,\n    PascAsl_f,\n    START_PSaaa_DFE,\n    _NAme_MYa_sayR,\n    NAme_MYa_sayR_\n}\n\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph1/naming/file/fileNameTest.kt",
    "content": "package com.saveourtool.diktat.resources.test.paragraph1.naming.file.resources.test.paragraph1.naming.file.naming.file\n\nfun foo () {\n\n}\n\nclass FileNameTest2 {\n}\n\nclass FileNameTest3 {\n\n}\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph1/naming/file/file_nameTest.kt",
    "content": "package com.saveourtool.diktat.resources.test.paragraph1.naming.file.resources.test.paragraph1.naming.file.resources.test.paragraph1.naming.file.naming.file\n\nclass FileNameTest1 {\n}\n\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph1/naming/function/FunctionNameExpected.kt",
    "content": "package com.saveourtool.diktat.ktlint.ruleset.standarddd\n\nimport com.saveourtool.diktat.ktlint.CORE.Rule\n\n/**\n * Alphabetical with capital letters before lower case letters (e.g. Z before a).\n * No blank lines between major groups (android, com, junit, net, org, java, javax).\n * Single group regardless of import type.\n *\n * https://developer.android.com/kotlin/style-guide#import_statements\n */\nclass TestPackageName {\n    fun METHOD1() {\n\n    }\n\n    fun method_two() {\n\n    }\n\n    fun methODTREE() {\n\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph1/naming/function/FunctionNameTest.kt",
    "content": "package com.saveourtool.diktat.ktlint.ruleset\n\nclass TestPackageName {\n    fun /* */ METHOD1(someName: String): Unit {\n\n    }\n\n    fun /* */ method_two(someName: String): Unit {\n        fun other_method_inside(): Boolean {\n            return false\n        }\n    }\n\n    fun /* */ methODTREE(someName: String) {\n\n    }\n}\n\n// incorrect case\nfun /* */ String.STRMETHOD1(someName: String): Unit {\n\n}\n\n// incorrect case\nfun /* */ String.str_method_two(someName: String): Unit {\n\n}\n\n// incorrect case\nfun /* */ String.strMethODTREE(): String {\n    return \"\"\n}\n\n// should be corrected to isValidIdentifier\nfun /* */ String.validIdentifier(): Boolean {\n    return false\n}\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph1/naming/generic/GenericFunctionExpected.kt",
    "content": "package com.saveourtool.diktat.test.paragraph1.naming.generic\n\nprivate class ClassName<T> {\n    private fun <Template, T> lock(body: ((Template?) -> T?)?, value: Template?): T? {\n        try {\n            val variableName: Template? = null\n            val variableT: T? = null\n            println(variableT)\n            return body!!(variableName)\n        } finally {\n            println()\n        }\n    }\n\n    fun foo(var1: T, var2: ((T?) -> T?)?) {\n        lock<T, T>(var2, var1)\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph1/naming/generic/GenericFunctionTest.kt",
    "content": "package com.saveourtool.diktat.test.paragraph1.naming.generic\n\nprivate class ClassName<T> {\n    private fun <Template, T> lock(body: ((Template?) -> T?)?, value: Template?): T? {\n        try {\n            val variableName: Template? = null\n            val variableT: T? = null\n            println(variableT)\n            return body!!(variableName)\n        } finally {\n            println()\n        }\n    }\n\n    fun foo(var1: T, var2: ((T?) -> T?)?) {\n        lock<T, T>(var2, var1)\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph1/naming/identifiers/ConstantValNameExpected.kt",
    "content": "package test.paragraph1.naming.identifiers\n\nprivate const val PASCAL_CASE = \"\"\nprivate const val LOWER = \"\"\nprivate const val LOWER_CAMEL = \"\"\nprivate const val LOWER_SNAKE = \"\"\nprivate const val AM_CONSTANT = \"\" // be careful - we have also replaced a prefix here\nprivate const val CODE = \"\" // prefix \"x\" - was removed\nprivate const val AM_CONSTANT1 = \"\"\nprivate const val STRANGE_NAME = \"\"\nprivate const val MY_STR_ANGE_NAME = \"\"\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph1/naming/identifiers/ConstantValNameTest.kt",
    "content": "package test.paragraph1.naming.identifiers\n\nprivate const val PascalCase = \"\"\nprivate const val lower = \"\"\nprivate const val lowerCamel = \"\"\nprivate const val lower_snake = \"\"\nprivate const val iAmConstant = \"\" // be careful - we have also replaced a prefix here\nprivate const val xCode = \"\" // prefix \"x\" - was removed\nprivate const val I_AM_CONSTANT1 = \"\"\nprivate const val STRANGE_name = \"\"\nprivate const val My_strAngeName = \"\"\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph1/naming/identifiers/IdentifierNameRegressionExpected.kt",
    "content": "package io.reflekt.plugin.utils\n\nobject Util {\n    private val getUses: String\n}\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph1/naming/identifiers/IdentifierNameRegressionTest.kt",
    "content": "package io.reflekt.plugin.utils\n\nobject Util {\n    private val GET_USES: String\n}\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph1/naming/identifiers/LambdaArgExpected.kt",
    "content": "package test.paragraph1.naming.identifiers\n\nprivate fun checkCommentedCode(node: ASTNode) {\n    val eolCommentsOffsetToText = \"\"\n    val blockCommentsOffsetToText = \"\"\n    (eolCommentsOffsetToText + blockCommentsOffsetToText)\n            .map { (strangecase, text) ->\n                \"\"\n            }\n}\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph1/naming/identifiers/LambdaArgTest.kt",
    "content": "package test.paragraph1.naming.identifiers\n\nprivate fun checkCommentedCode(node: ASTNode) {\n    val eolCommentsOffsetToText = \"\"\n    val blockCommentsOffsetToText = \"\"\n    (eolCommentsOffsetToText + blockCommentsOffsetToText)\n            .map { (STRANGECASE, text) ->\n                \"\"\n            }\n}\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph1/naming/identifiers/PrefixInNameExpected.kt",
    "content": "package test.paragraph1.naming.identifiers\n\nconst val GLOB = \"\"\nval prefix = \"\"\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph1/naming/identifiers/PrefixInNameTest.kt",
    "content": "package test.paragraph1.naming.identifiers\n\nconst val M_GLOB = \"\"\nval aPrefix = \"\"\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph1/naming/identifiers/PropertyInKdocExpected.kt",
    "content": "package test.paragraph1.naming.identifiers\n\n/**\n * @property anAbcMember\n * @property another_abc_member\n * @property anDefMember\n * @property anotherDefMember\n */\ndata class Abc(\n    private val anAbcMember: String,\n    val another_abc_member: String,\n) {\n    private val anDefMember: String = \"\"\n    private val anotherDefMember: String = \"\"\n}\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph1/naming/identifiers/PropertyInKdocTest.kt",
    "content": "package test.paragraph1.naming.identifiers\n\n/**\n * @property an_abc_member\n * @property another_abc_member\n * @property an_def_member\n * @property another_def_member\n */\ndata class abc(\n    private val an_abc_member: String,\n    val another_abc_member: String,\n) {\n    private val an_def_member: String = \"\"\n    private val another_def_member: String = \"\"\n}\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph1/naming/identifiers/TypeAliasNameExpected.kt",
    "content": "package test.paragraph1.naming.identifiers\n\nclass TypeAliasName {\n    typealias RelatedClasses = List<Pair<String, String>>\n}"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph1/naming/identifiers/TypeAliasNameTest.kt",
    "content": "package test.paragraph1.naming.identifiers\n\nclass TypeAliasName {\n    typealias relatedClasses = List<Pair<String, String>>\n}"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph1/naming/identifiers/VariableNamingExpected.kt",
    "content": "package test.paragraph1.naming.identifiers\n\nprivate var pascalCase = \"\"\nprivate var upper = \"\"\nprivate var upperSnake = \"\"\nprivate var lowerSnake = \"\"\nprivate val amConstant1 = \"\"\nprivate val strangeName = \"\"\nprivate val loWerValue = \"\"\nprivate val lower = \"\"\nprivate val valNx256 = \"\"\nprivate val voiceIpPort = \"\"\n\nclass A {\n    private val voiceIpPort = \"\"\n    public val valN_x2567 = \"\"\n\n    fun foo() {\n        val voiceIpPorts = \"\"\n        val upperSnakers = voiceIpPort\n        qww(voiceIpPorts)\n    }\n\n    fun goo() {\n        val qwe = lowerSnake\n        val pre = valNx256\n    }\n}\n\nclass B {\n    companion object {\n        val QQ = 1\n        private val qwe = 11\n    }\n\n    fun foo() {\n        var qq = 20\n        while (qq < 20) {\n            qq = 10\n        }\n    }\n\n    class Ba {\n        fun goo() {\n            val qwe = QQ\n        }\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph1/naming/identifiers/VariableNamingTest.kt",
    "content": "package test.paragraph1.naming.identifiers\n\nprivate var PascalCase = \"\"\nprivate var UPPER = \"\"\nprivate var UPPER_SNAKE = \"\"\nprivate var lower_snake = \"\"\nprivate val I_AM_CONSTANT1 = \"\"\nprivate val STRANGE_name = \"\"\nprivate val loWer_VAlue = \"\"\nprivate val lower = \"\"\nprivate val ValN_x256 = \"\"\nprivate val VoiceIP_port = \"\"\n\nclass A {\n    private val VoiceIP_port = \"\"\n    public val valN_x2567 = \"\"\n\n    fun foo() {\n        val VoiceIP_ports = \"\"\n        val UPPER_SNAKERS = VoiceIP_port\n        qww(VoiceIP_ports)\n    }\n\n    fun goo() {\n        val qwe = lower_snake\n        val pre = ValN_x256\n    }\n}\n\nclass B {\n    companion object {\n        val QQ = 1\n        private val QWE = 11\n    }\n\n    fun foo() {\n        var QQ = 20\n        while (QQ < 20) {\n            QQ = 10\n        }\n    }\n\n    class BA {\n        fun goo() {\n            val qwe = QQ\n        }\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph1/naming/object_/IncorrectObjectNameExpected.kt",
    "content": "package com.saveourtool.diktat.test.resources.test.paragraph1.naming.object_\n\nobject PaScalCase1 {}\nobject PascalCase2 {}\nobject PascalCase3 {}\nobject PascalCase4 {}\nobject Pascalcase5 {}\nobject Pascalcase6 {}\nobject PascAlCase7 {}\nobject PascaLcase8 {}\nobject PascAlCase9 {}\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph1/naming/object_/IncorrectObjectNameTest.kt",
    "content": "package com.saveourtool.diktat.test.resources.test.paragraph1.naming.object_\n\nobject PaScalCase1 {}\nobject Pascal_Case2 {}\nobject Pascal_case3 {}\nobject Pascal_Case4 {}\nobject Pascalcase5 {}\nobject Pascalcase6 {}\nobject PascAl_Case7 {}\nobject PascaL_Case8 {}\nobject PascAL_Case9 {}\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph1/naming/package/FixUnderscoreExpected.kt",
    "content": "package /* AAAAAA */    com.saveourtool.diktat.ktlint.ruleset.standarddd\n\nimport com.saveourtool.diktat.ktlint.CORE.Rule\n\n\n/**\n * some comments\n *\n */\nclass TestPackageName {\n    var dfsGGGG =\"\"\n}\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph1/naming/package/FixUnderscoreTest.kt",
    "content": "package /* AAAAAA */    com.saveourtool.diktat.ktlint.rule_set.standarddd\n\nimport com.saveourtool.diktat.ktlint.CORE.Rule\n\n\n/**\n * some comments\n *\n */\nclass TestPackageName {\n    var dfsGGGG =\"\"\n}\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph1/naming/package/FixUpperExpected.kt",
    "content": "package /* AAAAAA */    com.saveourtool.diktat.ktlint.ruleset.standarddd\n\nimport com.saveourtool.diktat.ktlint.CORE.Rule\n\n\n/**\n * some comments\n *\n */\nclass TestPackageName {\n    var dfsGGGG =\"\"\n}\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph1/naming/package/FixUpperTest.kt",
    "content": "package /* AAAAAA */    com.saveourtool.diktat.ktlint.ruleset.standarDDD\n\nimport com.saveourtool.diktat.ktlint.CORE.Rule\n\n\n/**\n * some comments\n *\n */\nclass TestPackageName {\n    var dfsGGGG =\"\"\n}\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph1/naming/package/MissingDomainNameExpected.kt",
    "content": "package /* AAAAAA */    com.saveourtool.diktat.ktlint.ruleset.standarddd\n\nimport com.saveourtool.diktat.ktlint.CORE.Rule\n\n\n/**\n * some comments\n *\n */\nclass TestPackageName {\n    var dfsGGGG =\"\"\n}\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph1/naming/package/MissingDomainNameTest.kt",
    "content": "package /* AAAAAA */    ktlint.ruleset.standarddd\n\nimport com.saveourtool.diktat.ktlint.CORE.Rule\n\n\n/**\n * some comments\n *\n */\nclass TestPackageName {\n    var dfsGGGG =\"\"\n}\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph1/naming/package/src/main/kotlin/com/saveourtool/diktat/some/name/FixIncorrectExpected.kt",
    "content": "package /* AAAAAA */    com.saveourtool.diktat.some.name\n\nimport com.saveourtool.diktat.ktlint.core.Rule\n\nclass TestPackageName {\n}\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph1/naming/package/src/main/kotlin/com/saveourtool/diktat/some/name/FixIncorrectTest.kt",
    "content": "package /* AAAAAA */    some.buggy.way.to\n\nimport com.saveourtool.diktat.ktlint.core.Rule\n\nclass TestPackageName {\n}\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph1/naming/package/src/main/kotlin/com/saveourtool/diktat/some/name/FixMissingExpected.kt",
    "content": "package com.saveourtool.diktat.some.name\nimport com.saveourtool.diktat.ktlint.core.Rule\n\nclass TestPackageName {\n}\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph1/naming/package/src/main/kotlin/com/saveourtool/diktat/some/name/FixMissingTest.kt",
    "content": "import com.saveourtool.diktat.ktlint.core.Rule\n\nclass TestPackageName {\n}\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph1/naming/package/src/main/kotlin/com/saveourtool/diktat/some/name/FixMissingWithAnnotationExpected.kt",
    "content": "@file:Suppress(\"CONSTANT_UPPERCASE\")\n\npackage com.saveourtool.diktat.some.name\nimport com.saveourtool.diktat.ktlint.core.Rule\n\nclass TestPackageName {\n}\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph1/naming/package/src/main/kotlin/com/saveourtool/diktat/some/name/FixMissingWithAnnotationExpected2.kt",
    "content": "@file:Suppress(\"CONSTANT_UPPERCASE\") // comment\npackage com.saveourtool.diktat.some.name\nimport com.saveourtool.diktat.ktlint.core.Rule\n\nclass TestPackageName {\n}\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph1/naming/package/src/main/kotlin/com/saveourtool/diktat/some/name/FixMissingWithAnnotationExpected3.kt",
    "content": "/**\n * comment\n */\n@file:Suppress(\"CONSTANT_UPPERCASE\")\npackage com.saveourtool.diktat.some.name\nimport com.saveourtool.diktat.ktlint.core.Rule\n\nclass TestPackageName {\n}\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph1/naming/package/src/main/kotlin/com/saveourtool/diktat/some/name/FixMissingWithAnnotationTest.kt",
    "content": "@file:Suppress(\"CONSTANT_UPPERCASE\")\n\nimport com.saveourtool.diktat.ktlint.core.Rule\n\nclass TestPackageName {\n}\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph1/naming/package/src/main/kotlin/com/saveourtool/diktat/some/name/FixMissingWithAnnotationTest2.kt",
    "content": "@file:Suppress(\"CONSTANT_UPPERCASE\") // comment\nimport com.saveourtool.diktat.ktlint.core.Rule\n\nclass TestPackageName {\n}\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph1/naming/package/src/main/kotlin/com/saveourtool/diktat/some/name/FixMissingWithAnnotationTest3.kt",
    "content": "/**\n * comment\n */\n@file:Suppress(\"CONSTANT_UPPERCASE\")\nimport com.saveourtool.diktat.ktlint.core.Rule\n\nclass TestPackageName {\n}\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph1/naming/package/src/main/kotlin/com/saveourtool/diktat/some/name/FixMissingWithoutImportExpected.kt",
    "content": "@file:Suppress(\"CONSTANT_UPPERCASE\")\npackage com.saveourtool.diktat.some.name\n\nval a = 5\n\nclass TestPackageName {\n}\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph1/naming/package/src/main/kotlin/com/saveourtool/diktat/some/name/FixMissingWithoutImportTest.kt",
    "content": "@file:Suppress(\"CONSTANT_UPPERCASE\")\nval a = 5\n\nclass TestPackageName {\n}\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph1/naming/package/src/main/kotlin/com/saveourtool/diktat/some/name/FixPackageRegressionExpected.kt",
    "content": "package com.saveourtool.diktat.some.name\n\nimport com.saveourtool.diktat.ktlint.core.Rule\n\nclass TestPackageName {\n}\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph1/naming/package/src/main/kotlin/com/saveourtool/diktat/some/name/FixPackageRegressionTest.kt",
    "content": "package app\n\nimport com.saveourtool.diktat.ktlint.core.Rule\n\nclass TestPackageName {\n}\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph1/naming/package/src/main/kotlin/some/FixIncorrectExpected.kt",
    "content": "package /* AAAAAA */    com.saveourtool.diktat.some\n\nimport com.saveourtool.diktat.ktlint.core.Rule\n\nclass TestPackageName {\n}\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph1/naming/package/src/main/kotlin/some/FixIncorrectTest.kt",
    "content": "package /* AAAAAA */    buggy.path\n\nimport com.saveourtool.diktat.ktlint.core.Rule\n\nclass TestPackageName {\n}\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph1/naming/package/src/main/kotlin/some/FixMissingExpected.kt",
    "content": "package com.saveourtool.diktat.some\nimport com.saveourtool.diktat.ktlint.core.Rule\n\nclass TestPackageName {\n}\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph1/naming/package/src/main/kotlin/some/FixMissingTest.kt",
    "content": "import com.saveourtool.diktat.ktlint.core.Rule\n\nclass TestPackageName {\n}\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph2/header/AutoCopyrightApplyPatternExpected.kt",
    "content": "/*\n    Copyright (c) Huawei Technologies Co., Ltd. 2020-%%YEAR%%. All rights reserved.\n*/\n\npackage test.paragraph2.header\n\nclass Example\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph2/header/AutoCopyrightApplyPatternTest.kt",
    "content": "package test.paragraph2.header\n\nclass Example\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph2/header/AutoCopyrightExpected.kt",
    "content": "/*\n    Copyright (c) Huawei Technologies Co., Ltd. 2020-%%YEAR%%. All rights reserved.\n*/\n\npackage test.paragraph2.header\n\nclass Example\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph2/header/AutoCopyrightTest.kt",
    "content": "package test.paragraph2.header\n\nclass Example\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph2/header/CopyrightAbsentInvalidPatternExpected.kt",
    "content": "/*\n    Copyright (c) My Company., Ltd. 2012-%%YEAR%%. All rights reserved.\n*/\n/**\n * Lorem ipsum\n * dolor sit amet\n */\n\npackage test.paragraph2.header\n\nimport com.saveourtool.diktat.example.A\nimport com.saveourtool.diktat.example.B\n\n/**\n * Example class\n */\nclass Example {\n    lateinit var map: Map<A, B>\n}\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph2/header/CopyrightAbsentInvalidPatternTest.kt",
    "content": "/**\n * Lorem ipsum\n * dolor sit amet\n */\n\npackage test.paragraph2.header\n\nimport com.saveourtool.diktat.example.A\nimport com.saveourtool.diktat.example.B\n\n/**\n * Example class\n */\nclass Example {\n    lateinit var map: Map<A, B>\n}\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph2/header/CopyrightDifferentYearExpected.kt",
    "content": "/*\n    Copyright (c) My Company., Ltd. 2012-%%YEAR%%. All rights reserved.\n*/\n/**\n * Lorem ipsum\n * dolor sit amet\n */\n\npackage test.paragraph2.header\n\nimport com.saveourtool.diktat.example.A\nimport com.saveourtool.diktat.example.B\n\n/**\n * Example class\n */\nclass Example {\n    lateinit var map: Map<A, B>\n}\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph2/header/CopyrightDifferentYearExpected2.kt",
    "content": "/*\n    Copyright (c) My Company., Ltd. 2021. All rights reserved.\n*/\n/**\n * Lorem ipsum\n * dolor sit amet\n */\n\npackage test.paragraph2.header\n\nimport com.saveourtool.diktat.example.A\nimport com.saveourtool.diktat.example.B\n\n/**\n * Example class\n */\nclass Example {\n    lateinit var map: Map<A, B>\n}\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph2/header/CopyrightDifferentYearTest.kt",
    "content": "/*\n    Copyright (c) My Company., Ltd. 2012-2019. All rights reserved.\n*/\n/**\n * Lorem ipsum\n * dolor sit amet\n */\n\npackage test.paragraph2.header\n\nimport com.saveourtool.diktat.example.A\nimport com.saveourtool.diktat.example.B\n\n/**\n * Example class\n */\nclass Example {\n    lateinit var map: Map<A, B>\n}\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph2/header/CopyrightDifferentYearTest2.kt",
    "content": "/*\n    Copyright (c) My Company., Ltd. 2003. All rights reserved.\n*/\n/**\n * Lorem ipsum\n * dolor sit amet\n */\n\npackage test.paragraph2.header\n\nimport com.saveourtool.diktat.example.A\nimport com.saveourtool.diktat.example.B\n\n/**\n * Example class\n */\nclass Example {\n    lateinit var map: Map<A, B>\n}\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph2/header/CopyrightInvalidPatternValidCodeExpected.kt",
    "content": "/*\n    Copyright (c) My Company., Ltd. 2021-%%YEAR%%. All rights reserved.\n*/\n/**\n * Lorem ipsum\n * dolor sit amet\n */\n\npackage test.paragraph2.header\n\nimport com.saveourtool.diktat.example.A\nimport com.saveourtool.diktat.example.B\n\n/**\n * Example class\n */\nclass Example {\n    lateinit var map: Map<A, B>\n}\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph2/header/CopyrightInvalidPatternValidCodeTest.kt",
    "content": "/*\n    Copyright (c) My Company., Ltd. 2021-%%YEAR%%. All rights reserved.\n*/\n/**\n * Lorem ipsum\n * dolor sit amet\n */\n\npackage test.paragraph2.header\n\nimport com.saveourtool.diktat.example.A\nimport com.saveourtool.diktat.example.B\n\n/**\n * Example class\n */\nclass Example {\n    lateinit var map: Map<A, B>\n}\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph2/header/CopyrightShouldNotTriggerNPEExpected.kt",
    "content": "/*\n    Copyright (c) My Company., Ltd. 2012-%%YEAR%%. All rights reserved.\n*/\n/**\n * Lorem ipsum\n * dolor sit amet\n */\n\npackage test.paragraph2.header\n\nimport com.saveourtool.diktat.example.A\nimport com.saveourtool.diktat.example.B\n\n/**\n * Example class\n */\nclass Example {\n    lateinit var map: Map<A, B>\n}\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph2/header/CopyrightShouldNotTriggerNPETest.kt",
    "content": "/**\n * Lorem ipsum\n * dolor sit amet\n */\n\npackage test.paragraph2.header\n\nimport com.saveourtool.diktat.example.A\nimport com.saveourtool.diktat.example.B\n\n/**\n * Example class\n */\nclass Example {\n    lateinit var map: Map<A, B>\n}\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph2/header/MisplacedHeaderKdocAppendedCopyrightExpected.kt",
    "content": "/*\n    Copyright (c) Huawei Technologies Co., Ltd. 2020-%%YEAR%%. All rights reserved.\n*/\n/**\n * Lorem ipsum\n * dolor sit amet\n */\n\npackage test.paragraph2.header\n\nimport com.saveourtool.diktat.example.A\nimport com.saveourtool.diktat.example.B\n\n/**\n * Example class\n */\nclass Example {\n    lateinit var map: Map<A, B>\n}\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph2/header/MisplacedHeaderKdocAppendedCopyrightTest.kt",
    "content": "package test.paragraph2.header\n\nimport com.saveourtool.diktat.example.A\nimport com.saveourtool.diktat.example.B\n\n/**\n * Lorem ipsum\n * dolor sit amet\n */\n\n/**\n * Example class\n */\nclass Example {\n    lateinit var map: Map<A, B>\n}\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph2/header/MisplacedHeaderKdocExpected.kt",
    "content": "/*\n    Copyright (c) Huawei Technologies Co., Ltd. 2020-%%YEAR%%. All rights reserved.\n*/\n/**\n * Lorem ipsum\n * dolor sit amet\n */\n\npackage test.paragraph2.header\n\nimport com.saveourtool.diktat.example.A\nimport com.saveourtool.diktat.example.B\n\n/**\n * Example class\n */\nclass Example {\n    lateinit var map: Map<A, B>\n}\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph2/header/MisplacedHeaderKdocNoCopyrightExpected.kt",
    "content": "/**\n * Lorem ipsum\n * dolor sit amet\n */\n\npackage test.paragraph2.header\n\nimport com.saveourtool.diktat.example.A\nimport com.saveourtool.diktat.example.B\n\n/**\n * Example class\n */\nclass Example {\n    lateinit var map: Map<A, B>\n}\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph2/header/MisplacedHeaderKdocNoCopyrightTest.kt",
    "content": "package test.paragraph2.header\n\nimport com.saveourtool.diktat.example.A\nimport com.saveourtool.diktat.example.B\n\n/**\n * Lorem ipsum\n * dolor sit amet\n */\n\n/**\n * Example class\n */\nclass Example {\n    lateinit var map: Map<A, B>\n}\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph2/header/MisplacedHeaderKdocTest.kt",
    "content": "/*\n    Copyright (c) Huawei Technologies Co., Ltd. 2020-%%YEAR%%. All rights reserved.\n*/\n\npackage test.paragraph2.header\n\nimport com.saveourtool.diktat.example.A\nimport com.saveourtool.diktat.example.B\n\n/**\n * Lorem ipsum\n * dolor sit amet\n */\n\n/**\n * Example class\n */\nclass Example {\n    lateinit var map: Map<A, B>\n}\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph2/header/MultilineCopyrightExample.kt",
    "content": "/*\n    Copyright 2018-%%YEAR%% John Doe.\n\n    Licensed under the Apache License, Version 2.0 (the \"License\");\n    you may not use this file except in compliance with the License.\n    You may obtain a copy of the License at\n\n        http://www.apache.org/licenses/LICENSE-2.0\n\n    Unless required by applicable law or agreed to in writing, software\n    distributed under the License is distributed on an \"AS IS\" BASIS,\n    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n    See the License for the specific language governing permissions and\n    limitations under the License.\n*/\n\nclass SomeClass {\n    fun coolFun() {\n        val a = 5\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph2/header/MultilineCopyrightNotTriggerExample.kt",
    "content": "/*\n    Copyright 2018-%%YEAR%% John Doe.\n\n    Licensed under the Apache License, Version 2.0 (the \"License\");\n    you may not use this file except in compliance with the License.\n    You may obtain a copy of the License at\n*/\n\npackage test.paragraph2.header\n\nclass SomeClass {\n    fun function() {\n\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph2/header/MultilineCopyrightNotTriggerTest.kt",
    "content": "/*\n    Copyright 2018-%%YEAR%% John Doe.\n\n    Licensed under the Apache License, Version 2.0 (the \"License\");\n    you may not use this file except in compliance with the License.\n    You may obtain a copy of the License at\n*/\n\npackage test.paragraph2.header\n\nclass SomeClass {\n    fun function() {\n\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph2/header/MultilineCopyrightTest.kt",
    "content": "class SomeClass {\n    fun coolFun() {\n        val a = 5\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph2/header/NewlineAfterHeaderKdocExpected.kt",
    "content": "/*\n    Copyright (c) Huawei Technologies Co., Ltd. 2020-%%YEAR%%. All rights reserved.\n*/\n/**\n * This is a file used in unit test\n */\n\npackage test.paragraph2.header\n\nclass Example\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph2/header/NewlineAfterHeaderKdocTest.kt",
    "content": "/*\n    Copyright (c) Huawei Technologies Co., Ltd. 2020-%%YEAR%%. All rights reserved.\n*/\n/**\n * This is a file used in unit test\n */\npackage test.paragraph2.header\n\nclass Example\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph2/kdoc/BasicTagsEmptyLineBeforeExpected.kt",
    "content": "package test.paragraph2.kdoc\n\nclass Example {\n    /**\n     * @param a integer parameter\n     */\n    fun test1(a: Int) = Unit\n\n    /**\n     * Description\n     *\n     * @param a integer parameter\n     */\n    fun test2(a: Int) = Unit\n\n    /**\n     * Description\n     * @see test2\n     *\n     * @param a integer parameter\n     */\n    fun test3(a: Int) = Unit\n\n    /**\n     * @param a integer parameter\n     */\n    fun test4(a: Int) = Unit\n}\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph2/kdoc/BasicTagsEmptyLineBeforeTest.kt",
    "content": "package test.paragraph2.kdoc\n\nclass Example {\n    /**\n     * @param a integer parameter\n     */\n    fun test1(a: Int) = Unit\n\n    /**\n     * Description\n     * @param a integer parameter\n     */\n    fun test2(a: Int) = Unit\n\n    /**\n     * Description\n     * @see test2\n     * @param a integer parameter\n     */\n    fun test3(a: Int) = Unit\n\n    /**\n     *\n     * @param a integer parameter\n     */\n    fun test4(a: Int) = Unit\n}\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph2/kdoc/BasicTagsEmptyLinesExpected.kt",
    "content": "package test.paragraph2.kdoc\n\n/**\n * @param a\n * @return\n * @throws IllegalStateException\n */\nfun test(a: Int) = 2 * a\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph2/kdoc/BasicTagsEmptyLinesTest.kt",
    "content": "package test.paragraph2.kdoc\n\n/**\n * @param a\n *\n * @return\n\n * @throws IllegalStateException\n */\nfun test(a: Int) = 2 * a\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph2/kdoc/ConstructorCommentExpected.kt",
    "content": "package test.paragraph2.kdoc\n\n/**\n * kdoc\n * class\n * comment\n *\n * @param name\n */\nclass A constructor(\n    name: String\n) {}\n\n/**\n * kdoc\n * class\n * comment\n *\n * @param name single-line comment\n */\nclass A constructor(\n    name: String\n) {}\n\n/**\n * kdoc\n * class\n * comment\n *\n * @param name\n *   block\n *   comment\n */\nclass A constructor(\n    name: String\n) {}\n\n/**\n * kdoc\n * class\n * comment\n *\n * @param name\n *   kdoc property\n *   comment\n */\nclass A constructor(\n    name: String\n) {}\n\n/**\n * kdoc\n * class\n * comment\n */\nclass A constructor(\n    /**\n     * @property name property\n     * comment\n     */\n    name: String\n) {}\n\n/**\n * kdoc\n * class\n * comment\n *\n * @property name\n */\nclass A constructor(\n    val name: String\n) {}\n\n/**\n * kdoc\n * class\n * comment\n *\n * @property name single-line comment\n */\nclass A constructor(\n    val name: String\n) {}\n\n/**\n * kdoc\n * class\n * comment\n *\n * @property name\n *   block\n *   comment\n */\nclass A constructor(\n    val name: String\n) {}\n\n/**\n * kdoc\n * class\n * comment\n *\n * @property name\n *   kdoc property\n *   comment\n */\nclass A constructor(\n    val name: String\n) {}\n\n/**\n * kdoc\n * class\n * comment\n */\nclass A constructor(\n    /**\n     * @property name property\n     * comment\n     */\n    val name: String\n) {}\n\n/**\n * kdoc\n * class\n * comment\n *\n * @param name\n */\nclass A constructor(\n    private val name: String\n) {}\n\n/**\n * kdoc\n * class\n * comment\n *\n * @param name single-line comment\n */\nclass A constructor(\n    private val name: String\n) {}\n\n/**\n * kdoc\n * class\n * comment\n *\n * @param name\n *   block\n *   comment\n */\nclass A constructor(\n    private val name: String\n) {}\n\n/**\n * kdoc\n * class\n * comment\n *\n * @param name\n *   kdoc property\n *   comment\n */\nclass A constructor(\n    private val name: String\n) {}\n\n/**\n * kdoc\n * class\n * comment\n */\nclass A constructor(\n    /**\n     * @property name property\n     * comment\n     */\n    private val name: String\n) {}\n\n/**\n * kdoc\n * class\n * comment\n *\n * @param K\n * @property openName single-line comment\n * @property openLastName\n *   block\n *   comment\n * @property openBirthDate\n *   kdoc property\n *   comment\n */\nopen class B<K : Any> constructor(\n    open val openName: String,\n    open val openLastName: String,\n    open val openBirthDate: String,\n    /**\n     * @property openAddr property\n     * comment\n     */\n    open val openAddr: String\n) {}\n\n/**\n * kdoc\n * class\n * comment\n *\n * @param K\n * @param P\n * @param G\n * @param privateName single-line comment\n * @property protectedName single-line comment\n * @property internalName single-line comment\n * @property openName single-line comment\n * @property name single-line comment\n * @param paramName single-line comment\n * @param privateLastName\n *   block\n *   comment\n * @property protectedLastName\n *   block\n *   comment\n * @property internalLastName\n *   block\n *   comment\n * @property openLastName\n *   block\n *   comment\n * @property lastName\n *   block\n *   comment\n * @param paramLastName\n *   block\n *   comment\n * @param privateBirthDate\n *   kdoc property\n *   comment\n * @property protectedBirthDate\n *   kdoc property\n *   comment\n * @property internalBirthDate\n *   kdoc property\n *   comment\n * @property openBirthDate\n *   kdoc property\n *   comment\n * @property birthDate\n *   kdoc property\n *   comment\n * @param paramBirthDate\n *   kdoc property\n *   comment\n */\nclass A<K : Any, P: Any, G: Any> constructor(\n    private val privateName: String,\n    protected val protectedName: String,\n    internal val internalName: String,\n    override val openName: String,\n    val name: String,\n    paramName: String,\n    private val privateLastName: String,\n    protected val protectedLastName: String,\n    internal val internalLastName: String,\n    override val openLastName: String,\n    val lastName: String,\n    paramLastName: String,\n    private val privateBirthDate: String,\n    protected val protectedBirthDate: String,\n    internal val internalBirthDate: String,\n    override val openBirthDate: String,\n    val birthDate: String,\n    paramBirthDate: String,\n    /**\n     * @property privateAddr property\n     * comment\n     */\n    private val privateAddr: String,\n    /**\n     * @property protectedAddr property\n     * comment\n     */\n    protected val protectedAddr: String,\n    /**\n     * @property internalAddr property\n     * comment\n     */\n    internal val internalAddr: String,\n    /**\n     * @property openAddr property\n     * comment\n     */\n    override val openAddr: String,\n    /**\n     * @property addr property\n     * comment\n     */\n    val addr: String,\n    /**\n     * @property paramAddr property\n     * comment\n     */\n    paramAddr: String,\n) : B<K>(), C<P>, D<G> {}\n\n/**\n * kdoc\n * class\n * comment\n *\n * @property as\n * @property keyAs\n */\nactual annotation class JsonSerialize(\n    actual val `as`: KClass<*>,\n    actual val keyAs: KClass<*>,\n)\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph2/kdoc/ConstructorCommentNewlineExpected.kt",
    "content": "package test.paragraph2.kdoc\n\n/**\n * @property param1\n * @property param2 first comment\n */\nclass Example(\n    val param1: String,\n    val param2: String, // second comment\n)\n\n/**\n * @property param1\n * @property param2 first comment\n */\nclass Example(\n    val param1: String,\n    val param2: String, /* second comment */\n)\n\n/**\n * @property param1\n * @property param2 first comment\n */\nclass Example(\n    val param1: String,\n    val param2: String, /** second comment */\n)\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph2/kdoc/ConstructorCommentNewlineTest.kt",
    "content": "package test.paragraph2.kdoc\n\nclass Example(\n    val param1: String, // first comment\n    val param2: String, // second comment\n)\n\nclass Example(\n    val param1: String, /* first comment */\n    val param2: String, /* second comment */\n)\n\nclass Example(\n    val param1: String, /** first comment */\n    val param2: String, /** second comment */\n)\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph2/kdoc/ConstructorCommentNoKDocExpected.kt",
    "content": "package test.paragraph2.kdoc\n\n/**\n * @param name\n */\nclass A constructor(\n    name: String\n) {}\n\n/**\n * @param name single-line comment\n */\nclass A constructor(\n    name: String\n) {}\n\n/**\n * @param name\n *   block\n *   comment\n */\nclass A constructor(\n    name: String\n) {}\n\n/**\n * @param name\n *   kdoc property\n *   comment\n */\nclass A constructor(\n    name: String\n) {}\n\nclass A constructor(\n    /**\n     * @property name property\n     * comment\n     */\n    name: String\n) {}\n\n/**\n * @property name\n */\nclass A constructor(\n    val name: String\n) {}\n\n/**\n * @property name single-line comment\n */\nclass A constructor(\n    val name: String\n) {}\n\n/**\n * @property name\n *   block\n *   comment\n */\nclass A constructor(\n    val name: String\n) {}\n\n/**\n * @property name\n *   kdoc property\n *   comment\n */\nclass A constructor(\n    val name: String\n) {}\n\nclass A constructor(\n    /**\n     * @property name property\n     * comment\n     */\n    val name: String\n) {}\n\n/**\n * @param name\n */\nclass A constructor(\n    private val name: String\n) {}\n\n/**\n * @param name single-line comment\n */\nclass A constructor(\n    private val name: String\n) {}\n\n/**\n * @param name\n *   block\n *   comment\n */\nclass A constructor(\n    private val name: String\n) {}\n\n/**\n * @param name\n *   kdoc property\n *   comment\n */\nclass A constructor(\n    private val name: String\n) {}\n\nclass A constructor(\n    /**\n     * @property name property\n     * comment\n     */\n    private val name: String\n) {}\n\n/**\n * @param K\n * @property openName single-line comment\n * @property openLastName\n *   block\n *   comment\n * @property openBirthDate\n *   kdoc property\n *   comment\n */\nopen class B<K : Any> constructor(\n    open val openName: String,\n    open val openLastName: String,\n    open val openBirthDate: String,\n    /**\n     * @property openAddr property\n     * comment\n     */\n    open val openAddr: String\n) {}\n\n/**\n * @param K\n * @param P\n * @param G\n * @param privateName single-line comment\n * @property protectedName single-line comment\n * @property internalName single-line comment\n * @property openName single-line comment\n * @property name single-line comment\n * @param paramName single-line comment\n * @param privateLastName\n *   block\n *   comment\n * @property protectedLastName\n *   block\n *   comment\n * @property internalLastName\n *   block\n *   comment\n * @property openLastName\n *   block\n *   comment\n * @property lastName\n *   block\n *   comment\n * @param paramLastName\n *   block\n *   comment\n * @param privateBirthDate\n *   kdoc property\n *   comment\n * @property protectedBirthDate\n *   kdoc property\n *   comment\n * @property internalBirthDate\n *   kdoc property\n *   comment\n * @property openBirthDate\n *   kdoc property\n *   comment\n * @property birthDate\n *   kdoc property\n *   comment\n * @param paramBirthDate\n *   kdoc property\n *   comment\n */\nclass A<K : Any, P: Any, G: Any> constructor(\n    private val privateName: String,\n    protected val protectedName: String,\n    internal val internalName: String,\n    override val openName: String,\n    val name: String,\n    paramName: String,\n    private val privateLastName: String,\n    protected val protectedLastName: String,\n    internal val internalLastName: String,\n    override val openLastName: String,\n    val lastName: String,\n    paramLastName: String,\n    private val privateBirthDate: String,\n    protected val protectedBirthDate: String,\n    internal val internalBirthDate: String,\n    override val openBirthDate: String,\n    val birthDate: String,\n    paramBirthDate: String,\n    /**\n     * @property privateAddr property\n     * comment\n     */\n    private val privateAddr: String,\n    /**\n     * @property protectedAddr property\n     * comment\n     */\n    protected val protectedAddr: String,\n    /**\n     * @property internalAddr property\n     * comment\n     */\n    internal val internalAddr: String,\n    /**\n     * @property openAddr property\n     * comment\n     */\n    override val openAddr: String,\n    /**\n     * @property addr property\n     * comment\n     */\n    val addr: String,\n    /**\n     * @property paramAddr property\n     * comment\n     */\n    paramAddr: String,\n) : B<K>(), C<P>, D<G> {}\n\n/**\n * @property as\n * @property keyAs\n */\nactual annotation class JsonSerialize(\n    actual val `as`: KClass<*>,\n    actual val keyAs: KClass<*>,\n)\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph2/kdoc/ConstructorCommentNoKDocTest.kt",
    "content": "package test.paragraph2.kdoc\n\nclass A constructor(\n    name: String\n) {}\n\nclass A constructor(\n    //single-line comment\n    name: String\n) {}\n\nclass A constructor(\n    /*\n     * block\n     * comment\n     */\n    name: String\n) {}\n\nclass A constructor(\n    /**\n     * kdoc property\n     * comment\n     */\n    name: String\n) {}\n\nclass A constructor(\n    /**\n     * @property name property\n     * comment\n     */\n    name: String\n) {}\n\nclass A constructor(\n    val name: String\n) {}\n\nclass A constructor(\n    //single-line comment\n    val name: String\n) {}\n\nclass A constructor(\n    /*\n     * block\n     * comment\n     */\n    val name: String\n) {}\n\nclass A constructor(\n    /**\n     * kdoc property\n     * comment\n     */\n    val name: String\n) {}\n\nclass A constructor(\n    /**\n     * @property name property\n     * comment\n     */\n    val name: String\n) {}\n\nclass A constructor(\n    private val name: String\n) {}\n\nclass A constructor(\n    //single-line comment\n    private val name: String\n) {}\n\nclass A constructor(\n    /*\n     * block\n     * comment\n     */\n    private val name: String\n) {}\n\nclass A constructor(\n    /**\n     * kdoc property\n     * comment\n     */\n    private val name: String\n) {}\n\nclass A constructor(\n    /**\n     * @property name property\n     * comment\n     */\n    private val name: String\n) {}\n\nopen class B<K : Any> constructor(\n    //single-line comment\n    open val openName: String,\n    /*\n     * block\n     * comment\n     */\n    open val openLastName: String,\n    /**\n     * kdoc property\n     * comment\n     */\n    open val openBirthDate: String,\n    /**\n     * @property openAddr property\n     * comment\n     */\n    open val openAddr: String\n) {}\n\nclass A<K : Any, P: Any, G: Any> constructor(\n    //single-line comment\n    private val privateName: String,\n    //single-line comment\n    protected val protectedName: String,\n    //single-line comment\n    internal val internalName: String,\n    //single-line comment\n    override val openName: String,\n    //single-line comment\n    val name: String,\n    //single-line comment\n    paramName: String,\n    /*\n     * block\n     * comment\n     */\n    private val privateLastName: String,\n    /*\n     * block\n     * comment\n     */\n    protected val protectedLastName: String,\n    /*\n     * block\n     * comment\n     */\n    internal val internalLastName: String,\n    /*\n     * block\n     * comment\n     */\n    override val openLastName: String,\n    /*\n     * block\n     * comment\n     */\n    val lastName: String,\n    /*\n     * block\n     * comment\n     */\n    paramLastName: String,\n    /**\n     * kdoc property\n     * comment\n     */\n    private val privateBirthDate: String,\n    /**\n     * kdoc property\n     * comment\n     */\n    protected val protectedBirthDate: String,\n    /**\n     * kdoc property\n     * comment\n     */\n    internal val internalBirthDate: String,\n    /**\n     * kdoc property\n     * comment\n     */\n    override val openBirthDate: String,\n    /**\n     * kdoc property\n     * comment\n     */\n    val birthDate: String,\n    /**\n     * kdoc property\n     * comment\n     */\n    paramBirthDate: String,\n    /**\n     * @property privateAddr property\n     * comment\n     */\n    private val privateAddr: String,\n    /**\n     * @property protectedAddr property\n     * comment\n     */\n    protected val protectedAddr: String,\n    /**\n     * @property internalAddr property\n     * comment\n     */\n    internal val internalAddr: String,\n    /**\n     * @property openAddr property\n     * comment\n     */\n    override val openAddr: String,\n    /**\n     * @property addr property\n     * comment\n     */\n    val addr: String,\n    /**\n     * @property paramAddr property\n     * comment\n     */\n    paramAddr: String,\n) : B<K>(), C<P>, D<G> {}\n\nactual annotation class JsonSerialize(\n    actual val `as`: KClass<*>,\n    actual val keyAs: KClass<*>,\n)\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph2/kdoc/ConstructorCommentPropertiesExpected.kt",
    "content": "package test.paragraph2.kdoc\n\n/**\n * @param name property info\n */\nclass A constructor(\n    name: String\n) {}\n\n/**\n * @param name property info\n *   single-line comment\n */\nclass A constructor(\n    name: String\n) {}\n\n/**\n * @param name property info\n *   block\n *   comment\n */\nclass A constructor(\n    name: String\n) {}\n\n/**\n * @param name property info\n *   kdoc property\n *   comment\n */\nclass A constructor(\n    name: String\n) {}\n\n/**\n * @param name property info\n */\nclass A constructor(\n    /**\n     * @property name property\n     * comment\n     */\n    name: String\n) {}\n\n/**\n * @property name property info\n */\nclass A constructor(\n    val name: String\n) {}\n\n/**\n * @property name property info\n *   single-line comment\n */\nclass A constructor(\n    val name: String\n) {}\n\n/**\n * @property name property info\n *   block\n *   comment\n */\nclass A constructor(\n    val name: String\n) {}\n\n/**\n * @property name property info\n *   kdoc property\n *   comment\n */\nclass A constructor(\n    val name: String\n) {}\n\n/**\n * @property name property info\n */\nclass A constructor(\n    /**\n     * @property name property\n     * comment\n     */\n    val name: String\n) {}\n\n/**\n * @param name property info\n */\nclass A constructor(\n    private val name: String\n) {}\n\n/**\n * @param name property info\n *   single-line comment\n */\nclass A constructor(\n    private val name: String\n) {}\n\n/**\n * @param name property info\n *   block\n *   comment\n */\nclass A constructor(\n    private val name: String\n) {}\n\n/**\n * @param name property info\n *   kdoc property\n *   comment\n */\nclass A constructor(\n    private val name: String\n) {}\n\n/**\n * @property name property info\n */\nclass A constructor(\n    /**\n     * @property name property\n     * comment\n     */\n    private val name: String\n) {}\n\n/**\n * @property openName open property info\n *   single-line comment\n * @property openLastName\n *   open last property\n *   info\n *   block\n *   comment\n * @property openAddr\n *   property\n *   info\n * @param K\n * @property openBirthDate\n *   kdoc property\n *   comment\n */\nopen class B<K : Any> constructor(\n    open val openName: String,\n    open val openLastName: String,\n    open val openBirthDate: String,\n    /**\n     * @property openAddr property\n     * comment\n     */\n    open val openAddr: String\n) {}\n\n/**\n * @param P generic type\n * @param K generic type\n * @property internalName internal\n *   property info\n *   single-line comment\n * @property openName override\n *   property info\n *   single-line comment\n * @param privateLastName private\n *   property info\n *   block\n *   comment\n * @property openAddr override\n *   property info\n * @param G\n * @param privateName single-line comment\n * @property protectedName single-line comment\n * @property name single-line comment\n * @param paramName single-line comment\n * @property protectedLastName\n *   block\n *   comment\n * @property internalLastName\n *   block\n *   comment\n * @property openLastName\n *   block\n *   comment\n * @property lastName\n *   block\n *   comment\n * @param paramLastName\n *   block\n *   comment\n * @param privateBirthDate\n *   kdoc property\n *   comment\n * @property protectedBirthDate\n *   kdoc property\n *   comment\n * @property internalBirthDate\n *   kdoc property\n *   comment\n * @property openBirthDate\n *   kdoc property\n *   comment\n * @property birthDate\n *   kdoc property\n *   comment\n * @param paramBirthDate\n *   kdoc property\n *   comment\n */\nclass A<K : Any, P: Any, G: Any> constructor(\n    private val privateName: String,\n    protected val protectedName: String,\n    internal val internalName: String,\n    override val openName: String,\n    val name: String,\n    paramName: String,\n    private val privateLastName: String,\n    protected val protectedLastName: String,\n    internal val internalLastName: String,\n    override val openLastName: String,\n    val lastName: String,\n    paramLastName: String,\n    private val privateBirthDate: String,\n    protected val protectedBirthDate: String,\n    internal val internalBirthDate: String,\n    override val openBirthDate: String,\n    val birthDate: String,\n    paramBirthDate: String,\n    /**\n     * @property privateAddr property\n     * comment\n     */\n    private val privateAddr: String,\n    /**\n     * @property protectedAddr property\n     * comment\n     */\n    protected val protectedAddr: String,\n    /**\n     * @property internalAddr property\n     * comment\n     */\n    internal val internalAddr: String,\n    /**\n     * @property openAddr property\n     * comment\n     */\n    override val openAddr: String,\n    /**\n     * @property addr property\n     * comment\n     */\n    val addr: String,\n    /**\n     * @property paramAddr property\n     * comment\n     */\n    paramAddr: String,\n) : B<K>(), C<P>, D<G> {}\n\n/**\n * @property keyAs\n * @property as\n */\nactual annotation class JsonSerialize(\n    actual val `as`: KClass<*>,\n    actual val keyAs: KClass<*>,\n)\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph2/kdoc/ConstructorCommentPropertiesTest.kt",
    "content": "package test.paragraph2.kdoc\n\n/**\n * @param name property info\n */\nclass A constructor(\n    name: String\n) {}\n\n/**\n * @param name property info\n */\nclass A constructor(\n    //single-line comment\n    name: String\n) {}\n\n/**\n * @param name property info\n */\nclass A constructor(\n    /*\n     * block\n     * comment\n     */\n    name: String\n) {}\n\n/**\n * @param name property info\n */\nclass A constructor(\n    /**\n     * kdoc property\n     * comment\n     */\n    name: String\n) {}\n\n/**\n * @param name property info\n */\nclass A constructor(\n    /**\n     * @property name property\n     * comment\n     */\n    name: String\n) {}\n\n/**\n * @property name property info\n */\nclass A constructor(\n    val name: String\n) {}\n\n/**\n * @property name property info\n */\nclass A constructor(\n    //single-line comment\n    val name: String\n) {}\n\n/**\n * @property name property info\n */\nclass A constructor(\n    /*\n     * block\n     * comment\n     */\n    val name: String\n) {}\n\n/**\n * @property name property info\n */\nclass A constructor(\n    /**\n     * kdoc property\n     * comment\n     */\n    val name: String\n) {}\n\n/**\n * @property name property info\n */\nclass A constructor(\n    /**\n     * @property name property\n     * comment\n     */\n    val name: String\n) {}\n\n/**\n * @property name property info\n */\nclass A constructor(\n    private val name: String\n) {}\n\n/**\n * @property name property info\n */\nclass A constructor(\n    //single-line comment\n    private val name: String\n) {}\n\n/**\n * @property name property info\n */\nclass A constructor(\n    /*\n     * block\n     * comment\n     */\n    private val name: String\n) {}\n\n/**\n * @property name property info\n */\nclass A constructor(\n    /**\n     * kdoc property\n     * comment\n     */\n    private val name: String\n) {}\n\n/**\n * @property name property info\n */\nclass A constructor(\n    /**\n     * @property name property\n     * comment\n     */\n    private val name: String\n) {}\n\n/**\n * @property openName open property info\n * @param openLastName\n *   open last property\n *   info\n * @property openAddr\n *   property\n *   info\n */\nopen class B<K : Any> constructor(\n    //single-line comment\n    open val openName: String,\n    /*\n     * block\n     * comment\n     */\n    open val openLastName: String,\n    /**\n     * kdoc property\n     * comment\n     */\n    open val openBirthDate: String,\n    /**\n     * @property openAddr property\n     * comment\n     */\n    open val openAddr: String\n) {}\n\n/**\n * @property P generic type\n * @param K generic type\n * @property internalName internal\n *   property info\n * @param openName override\n *   property info\n * @property privateLastName private\n *   property info\n * @property openAddr override\n *   property info\n */\nclass A<K : Any, P: Any, G: Any> constructor(\n    //single-line comment\n    private val privateName: String,\n    //single-line comment\n    protected val protectedName: String,\n    //single-line comment\n    internal val internalName: String,\n    //single-line comment\n    override val openName: String,\n    //single-line comment\n    val name: String,\n    //single-line comment\n    paramName: String,\n    /*\n     * block\n     * comment\n     */\n    private val privateLastName: String,\n    /*\n     * block\n     * comment\n     */\n    protected val protectedLastName: String,\n    /*\n     * block\n     * comment\n     */\n    internal val internalLastName: String,\n    /*\n     * block\n     * comment\n     */\n    override val openLastName: String,\n    /*\n     * block\n     * comment\n     */\n    val lastName: String,\n    /*\n     * block\n     * comment\n     */\n    paramLastName: String,\n    /**\n     * kdoc property\n     * comment\n     */\n    private val privateBirthDate: String,\n    /**\n     * kdoc property\n     * comment\n     */\n    protected val protectedBirthDate: String,\n    /**\n     * kdoc property\n     * comment\n     */\n    internal val internalBirthDate: String,\n    /**\n     * kdoc property\n     * comment\n     */\n    override val openBirthDate: String,\n    /**\n     * kdoc property\n     * comment\n     */\n    val birthDate: String,\n    /**\n     * kdoc property\n     * comment\n     */\n    paramBirthDate: String,\n    /**\n     * @property privateAddr property\n     * comment\n     */\n    private val privateAddr: String,\n    /**\n     * @property protectedAddr property\n     * comment\n     */\n    protected val protectedAddr: String,\n    /**\n     * @property internalAddr property\n     * comment\n     */\n    internal val internalAddr: String,\n    /**\n     * @property openAddr property\n     * comment\n     */\n    override val openAddr: String,\n    /**\n     * @property addr property\n     * comment\n     */\n    val addr: String,\n    /**\n     * @property paramAddr property\n     * comment\n     */\n    paramAddr: String,\n) : B<K>(), C<P>, D<G> {}\n\n/**\n * @property keyAs\n */\nactual annotation class JsonSerialize(\n    actual val `as`: KClass<*>,\n    actual val keyAs: KClass<*>,\n)\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph2/kdoc/ConstructorCommentTest.kt",
    "content": "package test.paragraph2.kdoc\n\n/**\n * kdoc\n * class\n * comment\n */\nclass A constructor(\n    name: String\n) {}\n\n/**\n * kdoc\n * class\n * comment\n */\nclass A constructor(\n    //single-line comment\n    name: String\n) {}\n\n/**\n * kdoc\n * class\n * comment\n */\nclass A constructor(\n    /*\n     * block\n     * comment\n     */\n    name: String\n) {}\n\n/**\n * kdoc\n * class\n * comment\n */\nclass A constructor(\n    /**\n     * kdoc property\n     * comment\n     */\n    name: String\n) {}\n\n/**\n * kdoc\n * class\n * comment\n */\nclass A constructor(\n    /**\n     * @property name property\n     * comment\n     */\n    name: String\n) {}\n\n/**\n * kdoc\n * class\n * comment\n */\nclass A constructor(\n    val name: String\n) {}\n\n/**\n * kdoc\n * class\n * comment\n */\nclass A constructor(\n    //single-line comment\n    val name: String\n) {}\n\n/**\n * kdoc\n * class\n * comment\n */\nclass A constructor(\n    /*\n     * block\n     * comment\n     */\n    val name: String\n) {}\n\n/**\n * kdoc\n * class\n * comment\n */\nclass A constructor(\n    /**\n     * kdoc property\n     * comment\n     */\n    val name: String\n) {}\n\n/**\n * kdoc\n * class\n * comment\n */\nclass A constructor(\n    /**\n     * @property name property\n     * comment\n     */\n    val name: String\n) {}\n\n/**\n * kdoc\n * class\n * comment\n */\nclass A constructor(\n    private val name: String\n) {}\n\n/**\n * kdoc\n * class\n * comment\n */\nclass A constructor(\n    //single-line comment\n    private val name: String\n) {}\n\n/**\n * kdoc\n * class\n * comment\n */\nclass A constructor(\n    /*\n     * block\n     * comment\n     */\n    private val name: String\n) {}\n\n/**\n * kdoc\n * class\n * comment\n */\nclass A constructor(\n    /**\n     * kdoc property\n     * comment\n     */\n    private val name: String\n) {}\n\n/**\n * kdoc\n * class\n * comment\n */\nclass A constructor(\n    /**\n     * @property name property\n     * comment\n     */\n    private val name: String\n) {}\n\n/**\n * kdoc\n * class\n * comment\n */\nopen class B<K : Any> constructor(\n    //single-line comment\n    open val openName: String,\n    /*\n     * block\n     * comment\n     */\n    open val openLastName: String,\n    /**\n     * kdoc property\n     * comment\n     */\n    open val openBirthDate: String,\n    /**\n     * @property openAddr property\n     * comment\n     */\n    open val openAddr: String\n) {}\n\n/**\n * kdoc\n * class\n * comment\n */\nclass A<K : Any, P: Any, G: Any> constructor(\n    //single-line comment\n    private val privateName: String,\n    //single-line comment\n    protected val protectedName: String,\n    //single-line comment\n    internal val internalName: String,\n    //single-line comment\n    override val openName: String,\n    //single-line comment\n    val name: String,\n    //single-line comment\n    paramName: String,\n    /*\n     * block\n     * comment\n     */\n    private val privateLastName: String,\n    /*\n     * block\n     * comment\n     */\n    protected val protectedLastName: String,\n    /*\n     * block\n     * comment\n     */\n    internal val internalLastName: String,\n    /*\n     * block\n     * comment\n     */\n    override val openLastName: String,\n    /*\n     * block\n     * comment\n     */\n    val lastName: String,\n    /*\n     * block\n     * comment\n     */\n    paramLastName: String,\n    /**\n     * kdoc property\n     * comment\n     */\n    private val privateBirthDate: String,\n    /**\n     * kdoc property\n     * comment\n     */\n    protected val protectedBirthDate: String,\n    /**\n     * kdoc property\n     * comment\n     */\n    internal val internalBirthDate: String,\n    /**\n     * kdoc property\n     * comment\n     */\n    override val openBirthDate: String,\n    /**\n     * kdoc property\n     * comment\n     */\n    val birthDate: String,\n    /**\n     * kdoc property\n     * comment\n     */\n    paramBirthDate: String,\n    /**\n     * @property privateAddr property\n     * comment\n     */\n    private val privateAddr: String,\n    /**\n     * @property protectedAddr property\n     * comment\n     */\n    protected val protectedAddr: String,\n    /**\n     * @property internalAddr property\n     * comment\n     */\n    internal val internalAddr: String,\n    /**\n     * @property openAddr property\n     * comment\n     */\n    override val openAddr: String,\n    /**\n     * @property addr property\n     * comment\n     */\n    val addr: String,\n    /**\n     * @property paramAddr property\n     * comment\n     */\n    paramAddr: String,\n) : B<K>(), C<P>, D<G> {}\n\n/**\n * kdoc\n * class\n * comment\n */\nactual annotation class JsonSerialize(\n    actual val `as`: KClass<*>,\n    actual val keyAs: KClass<*>,\n)\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph2/kdoc/DeprecatedTagExpected.kt",
    "content": "package test.paragraph2.kdoc\n\n/**\n * Example class\n */\n@Deprecated(message = \"Use class B instead\")\nclass A\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph2/kdoc/DeprecatedTagTest.kt",
    "content": "package test.paragraph2.kdoc\n\n/**\n * Example class\n * @deprecated Use class B instead\n */\nclass A\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph2/kdoc/KdocBlockCommentExpected.kt",
    "content": "package test.paragraph2.kdoc\n\n/**\n * Converts this AST node and all its children to pretty string representation\n */\n@Suppress(\"AVOID_NESTED_FUNCTIONS\")\nfun Example.prettyPrint(level: Int = 0, maxLevel: Int = -1): String {\n    /**\n     * AST operates with \\n only, so we need to build the whole string representation and then change line separator\n     */\n    fun Example.doPrettyPrint(level: Int, maxLevel: Int): String {\n        return \"test\" + level + maxLevel\n    }\n    return doPrettyPrint(level, maxLevel).replace(\"\\n\", System.lineSeparator())\n}\n\n/**\n * right place for kdoc\n */\nclass Example {\n    /**\n     * right place for kdoc\n     */\n    fun doGood() {\n        /*\n         * wrong place for kdoc\n         */\n        /*\n         * right place for block comment\n        */\n        // right place for eol comment\n        1 + 2\n        /**\n         * Converts this AST node and all its children to pretty string representation\n         */\n        fun Example.prettyPrint(level: Int = 0, maxLevel: Int = -1): String {\n            return \"test\"\n        }\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph2/kdoc/KdocBlockCommentTest.kt",
    "content": "package test.paragraph2.kdoc\n\n/**\n * Converts this AST node and all its children to pretty string representation\n */\n@Suppress(\"AVOID_NESTED_FUNCTIONS\")\nfun Example.prettyPrint(level: Int = 0, maxLevel: Int = -1): String {\n    /**\n     * AST operates with \\n only, so we need to build the whole string representation and then change line separator\n     */\n    fun Example.doPrettyPrint(level: Int, maxLevel: Int): String {\n        return \"test\" + level + maxLevel\n    }\n    return doPrettyPrint(level, maxLevel).replace(\"\\n\", System.lineSeparator())\n}\n\n/**\n * right place for kdoc\n */\nclass Example {\n    /**\n     * right place for kdoc\n     */\n    fun doGood() {\n        /**\n         * wrong place for kdoc\n         */\n        /*\n         * right place for block comment\n        */\n        // right place for eol comment\n        1 + 2\n        /**\n         * Converts this AST node and all its children to pretty string representation\n         */\n        fun Example.prettyPrint(level: Int = 0, maxLevel: Int = -1): String {\n            return \"test\"\n        }\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph2/kdoc/KdocCodeBlockFormattingExampleExpected.kt",
    "content": "package test.paragraph2.kdoc\n\n/**\n * This is the short overview comment for the example interface.\n *                   /* Add a blank line between the general comment text and each KDoc tag */\n * @since 1.6\n */\npublic interface Example {\n    // Some comments  /* Since it is the first member definition in this code block, there is no need to add a blank line here */\n    val aField: String\n\n// Some comments\n    val bField: String\n\n/**\n     * This is a long comment with whitespace that should be split in\n     * multiple line comments in case the line comment formatting is enabled.\n     *                /* blank line between description and Kdoc tag */\n     * @return the rounds of battle of fox and dog\n     */\n    fun foo()\n\n    /**\n     * These possibilities include: Formatting of header comments\n     * @return the rounds of battle of fox and dog\n     */\n    fun bar() {\n        // Some comments  /* Since it is the first member definition in this range, there is no need to add a blank line here */\n        var aVar = 5\n\n        // Some comments  /* Add a blank line above the comment */\n        fun doSome() {\n\n        }\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph2/kdoc/KdocCodeBlockFormattingExampleTest.kt",
    "content": "package test.paragraph2.kdoc\n\n/**\n * This is the short overview comment for the example interface.\n *                   /* Add a blank line between the general comment text and each KDoc tag */\n * @since 1.6\n */\npublic interface Example {\n    // Some comments  /* Since it is the first member definition in this code block, there is no need to add a blank line here */\n    val aField: String\n    // Some comments\n    val bField: String\n    /**\n     * This is a long comment with whitespace that should be split in\n     * multiple line comments in case the line comment formatting is enabled.\n     *                /* blank line between description and Kdoc tag */\n     * @return the rounds of battle of fox and dog\n     */\n    fun foo()\n\n    /**\n     * These possibilities include: Formatting of header comments\n     * @return the rounds of battle of fox and dog\n     */\n    fun bar() {\n        // Some comments  /* Since it is the first member definition in this range, there is no need to add a blank line here */\n        var aVar = 5\n\n        // Some comments  /* Add a blank line above the comment */\n        fun doSome() {\n\n        }\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph2/kdoc/KdocCodeBlocksFormattingExpected.kt",
    "content": "package test.paragraph2.kdoc\n\n/**\n * This is a test kDoc Comment\n */\nclass SomeClass {\n/* block comment to func */\n    fun testFunc() {\n        val a = 5  // Right side comment good\n        val c = 6  // Side comment\n\n        when (this) {\n            is AnotherClass -> println()\n            // Comment\n            is Any -> println()\n        }\n\n        /* General if comment */\n        if (a == 5) {\n\n        }\n        else {\n// Some Comment\n        }\n\n        if (a == 5) {\n\n        }\n        else\n// Some Comment\n            print(a)\n        /* Block Comment */\n        val some = 4\n\n        /* This is a block comment */\n\n        /*\n            Don't fix this comment\n        */\n    }\n\n    /**\n     * Useless kdoc comment\n     * Line\n     */\n\n    /**\n     *     This is a useless function\n     */\n    fun someUselessFunction() {\n// This is a useless value\n        val uselessValue = 1\n    }\n\n// Class comment\n    val b = 6\n\n/* Comment to this useless func*/\n    fun anotherUselessFunc() {\n\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph2/kdoc/KdocCodeBlocksFormattingTest.kt",
    "content": "package test.paragraph2.kdoc\n\n/**\n * This is a test kDoc Comment\n */\nclass SomeClass {\n\n    /* block comment to func */\n    fun testFunc() {\n        val a = 5//Right side comment good\n        val c = 6   // Side comment\n\n        when (this) {\n            is AnotherClass -> println()\n            // Comment\n            is Any -> println()\n        }\n\n        /* General if comment */\n        if (a == 5) {\n\n        }\n        // Some Comment\n        else {\n        }\n\n        if (a == 5) {\n\n        }\n        // Some Comment\n        else\n            print(a)\n        /* Block Comment */\n        val some = 4\n\n        /*This is a block comment */\n\n        /*\n            Don't fix this comment\n        */\n    }\n\n    /**\n     *Useless kdoc comment\n     *Line\n     */\n\n    /**\n     *     This is a useless function\n     */\n    fun someUselessFunction() {\n\n        //This is a useless value\n        val uselessValue = 1\n    }\n    // Class comment\n    val b = 6\n/* Comment to this useless func*/\n    fun anotherUselessFunc() {\n\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph2/kdoc/KdocEmptyLineExpected.kt",
    "content": "package com.saveourtool.diktat.test.resources.test.paragraph2.kdoc\n\n/**\n * declaration for some constant\n */\nconst val SUPER_CONSTANT = 46\n\n/**\n * Kdoc docummentation\n */\nclass SomeName {\n    /**\n     * another Kdoc\n     */\n    val a = \"string\"\n\n    /**\n     * another Kdoc\n     */\n    fun somePublicFunction() {}\n\n}\n\n/**\n * another Kdoc\n */\nfun someFunction() {}\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph2/kdoc/KdocEmptyLineTest.kt",
    "content": "package com.saveourtool.diktat.test.resources.test.paragraph2.kdoc\n\n/**\n * declaration for some constant\n */\n\nconst val SUPER_CONSTANT = 46\n\n/**\n * Kdoc docummentation\n */\n\nclass SomeName {\n    /**\n     * another Kdoc\n     */\n\n    val a = \"string\"\n\n    /**\n     * another Kdoc\n     */\n\n    fun somePublicFunction() {}\n\n}\n\n/**\n * another Kdoc\n */\n\nfun someFunction() {}\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph2/kdoc/KdocFormattingFullExpected.kt",
    "content": "package test.paragraph2.kdoc\n\nclass Example {\n\n    /**\n     * Empty function to test KDocs\n     * @apiNote stuff\n     *\n     * @implSpec spam\n     *\n     * Another line of description\n     *\n     * @param a useless integer\n     * @return doubled value\n     * @throws RuntimeException never\n     */\n    @Deprecated(message = \"Use testNew\")\n    fun test(a: Int): Int = 2 * a\n}\n\nclass Foo {\n    /**\n     * @implNote lorem ipsum\n     */\n    private fun foo() {}\n}\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph2/kdoc/KdocFormattingFullTest.kt",
    "content": "package test.paragraph2.kdoc\n\nclass Example {\n\n    /**\n     * Empty function to test KDocs\n     * @deprecated   Use testNew\n     * @apiNote stuff\n     * @implSpec   spam\n     *\n     * Another line of description\n     * @param   a   useless integer\n\n     * @throws RuntimeException never\n     *\n     * @return doubled value\n     */\n    fun test(a: Int): Int = 2 * a\n}\n\nclass Foo {\n    /**\n     * @implNote lorem ipsum\n     */\n    private fun foo() {}\n}\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph2/kdoc/KdocFormattingOrderExpected.kt",
    "content": "package test.paragraph2.kdoc\n\n/**\n * Creates a docker container with [file], prepared to execute it\n *\n * @param runConfiguration a [RunConfiguration] for the supplied binary\n * @param file a file that will be included as an executable\n * @param resources additional resources\n * @return id of created container or null if it wasn't created\n * @throws DockerException if docker daemon has returned an error\n * @throws DockerException if docker daemon has returned an error\n * @throws RuntimeException if an exception not specific to docker has occurred\n */\ninternal fun createWithFile(runConfiguration: RunConfiguration,\n                            containerName: String,\n                            file: File,\n                            resources: Collection<File> = emptySet()): String {}"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph2/kdoc/KdocFormattingOrderTest.kt",
    "content": "package test.paragraph2.kdoc\n\n/**\n * Creates a docker container with [file], prepared to execute it\n *\n * @param runConfiguration a [RunConfiguration] for the supplied binary\n * @param file a file that will be included as an executable\n * @param resources additional resources\n * @throws DockerException if docker daemon has returned an error\n * @throws DockerException if docker daemon has returned an error\n * @throws RuntimeException if an exception not specific to docker has occurred\n * @return id of created container or null if it wasn't created\n */\ninternal fun createWithFile(runConfiguration: RunConfiguration,\n                            containerName: String,\n                            file: File,\n                            resources: Collection<File> = emptySet()): String {}"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph2/kdoc/NoPackageNoImportExpected.kt",
    "content": "/**\n * Dolor sit amet\n */\nclass Example"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph2/kdoc/NoPackageNoImportTest.kt",
    "content": "/**\n * Dolor sit amet\n */\nclass Example"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph2/kdoc/OrderedTagsAssertionExpected.kt",
    "content": "package com.saveourtool.save.reporter.json\n\n/**\n * Reporter that produces a JSON report as a [Report]\n *\n * @param builder additional configuration lambda for serializers module\n * @property out a sink for output\n */\nclass JsonReporter(\n    override val out: BufferedSink,\n    builder: PolymorphicModuleBuilder<Plugin.TestFiles>.() -> Unit = {}\n) : Reporter\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph2/kdoc/OrderedTagsAssertionTest.kt",
    "content": "package com.saveourtool.save.reporter.json\n\n/**\n * Reporter that produces a JSON report as a [Report]\n *\n * @property out a sink for output\n *\n * @param builder additional configuration lambda for serializers module\n */\nclass JsonReporter(\n    override val out: BufferedSink,\n    builder: PolymorphicModuleBuilder<Plugin.TestFiles>.() -> Unit = {}\n) : Reporter\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph2/kdoc/OrderedTagsExpected.kt",
    "content": "package test.paragraph2.kdoc\n\nclass OrderedTags {\n\n    /**\n     * Empty function to test KDocs\n     *\n     * @param a useless integer\n     * @return Unit\n     * @throws RuntimeException never\n     */\n    fun test(a: Int) = Unit\n}\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph2/kdoc/OrderedTagsTest.kt",
    "content": "package test.paragraph2.kdoc\n\nclass OrderedTags {\n\n    /**\n     * Empty function to test KDocs\n     *\n     * @return Unit\n     * @throws RuntimeException never\n     * @param a useless integer\n     */\n    fun test(a: Int) = Unit\n}\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph2/kdoc/SpacesAfterTagExpected.kt",
    "content": "package test.paragraph2.kdoc\n\nclass SpacesAfterTag {\n\n    /**\n     * Empty function to test KDocs\n     *\n     * @param a useless integer\n     * @return\n     * @throws RuntimeException never\n     */\n    fun test(a: Int) = Unit\n}\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph2/kdoc/SpacesAfterTagTest.kt",
    "content": "package test.paragraph2.kdoc\n\nclass SpacesAfterTag {\n\n    /**\n     * Empty function to test KDocs\n     *\n     * @param  a useless integer\n     * @return\n     * @throws    RuntimeException never\n     */\n    fun test(a: Int) = Unit\n}\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph2/kdoc/SpecialTagsInKdocExpected.kt",
    "content": "package test.paragraph2.kdoc\n\nclass SpecialTagsInKdoc {\n\n    /**\n     * Empty function to test KDocs\n     * @apiNote foo\n     *\n     * @implSpec bar\n     *\n     * @implNote baz\n     */\n    fun test() = Unit\n}\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph2/kdoc/SpecialTagsInKdocTest.kt",
    "content": "package test.paragraph2.kdoc\n\nclass SpecialTagsInKdoc {\n\n    /**\n     * Empty function to test KDocs\n     * @apiNote foo\n     * @implSpec bar\n     *\n     *\n     * @implNote baz\n     */\n    fun test() = Unit\n}\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph2/kdoc/package/src/main/kotlin/com/saveourtool/diktat/kdoc/methods/EmptyKdocExpected.kt",
    "content": "package com.saveourtool.diktat.kdoc.methods\n\nval foo = 42\n\nfun doNothing() {\n    return\n}\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph2/kdoc/package/src/main/kotlin/com/saveourtool/diktat/kdoc/methods/EmptyKdocTested.kt",
    "content": "package com.saveourtool.diktat.kdoc.methods\n\nval foo = 42\n\nfun doNothing() {\n    return\n}\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph2/kdoc/package/src/main/kotlin/com/saveourtool/diktat/kdoc/methods/KdocMethodsFullExpected.kt",
    "content": "package com.saveourtool.diktat.kdoc.methods\n\nclass KdocMethodsFull {\n    fun test1() {\n        // this function does nothing\n    }\n\n    /**\n     * This function is described\n     * partially.\n     * @param a\n     * @return\n     */\n    fun test2(a: Int): Int {\n        return 2 * a\n    }\n\n    companion object {\n        /**\n * @param a\n * @throws IllegalStateException\n */\nfun test3(a: Int) {\n            throw IllegalStateException(\"Lorem ipsum\")\n        }\n    }\n\n    private class Nested {\n        /**\n * @param a\n * @param b\n * @return\n */\nfun test4(a: Int, b: Int): Int = 42\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph2/kdoc/package/src/main/kotlin/com/saveourtool/diktat/kdoc/methods/KdocMethodsFullTested.kt",
    "content": "package com.saveourtool.diktat.kdoc.methods\n\nclass KdocMethodsFull {\n    fun test1() {\n        // this function does nothing\n    }\n\n    /**\n     * This function is described\n     * partially.\n     */\n    fun test2(a: Int): Int {\n        return 2 * a\n    }\n\n    companion object {\n        fun test3(a: Int) {\n            throw IllegalStateException(\"Lorem ipsum\")\n        }\n    }\n\n    private class Nested {\n        fun test4(a: Int, b: Int): Int = 42\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph2/kdoc/package/src/main/kotlin/com/saveourtool/diktat/kdoc/methods/KdocWithoutThrowsTagExpected.kt",
    "content": "package test.paragraph2.kdoc.`package`.src.main.kotlin.com.saveourtool.diktat.kdoc.methods\n\n/**\n * @param onSuccess\n * @param onFailure\n * @throws ArrayIndexOutOfBounds\n */\nfun parseInputNumber(onSuccess: (number: Int) -> Unit, onFailure: () -> Unit) {\n    try {\n        val input: Int = binding.inputEditText.text.toString().toInt()\n        if (input < 0)\n            throw NumberFormatException()\n        throw ArrayIndexOutOfBounds()\n        throw NullPointerException()\n\n        onSuccess(input)\n    } catch (e: IllegalArgumentException) {\n        onFailure()\n    } catch (e: NullPointerException) {\n        onFailure()\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph2/kdoc/package/src/main/kotlin/com/saveourtool/diktat/kdoc/methods/KdocWithoutThrowsTagTested.kt",
    "content": "package test.paragraph2.kdoc.`package`.src.main.kotlin.com.saveourtool.diktat.kdoc.methods\n\n/**\n * @param onSuccess\n * @param onFailure\n */\nfun parseInputNumber(onSuccess: (number: Int) -> Unit, onFailure: () -> Unit) {\n    try {\n        val input: Int = binding.inputEditText.text.toString().toInt()\n        if (input < 0)\n            throw NumberFormatException()\n        throw ArrayIndexOutOfBounds()\n        throw NullPointerException()\n\n        onSuccess(input)\n    } catch (e: IllegalArgumentException) {\n        onFailure()\n    } catch (e: NullPointerException) {\n        onFailure()\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph2/kdoc/package/src/main/kotlin/com/saveourtool/diktat/kdoc/methods/MissingKdocExpected.kt",
    "content": "package com.saveourtool.diktat.kdoc.methods\n\nclass Example {\n    /**\n * @param a\n * @param b\n * @return\n * @throws IllegalStateException\n */\nfun addInts(a: Int, b: Int): Int {\n        if (false) throw IllegalStateException()\n        return a + b\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph2/kdoc/package/src/main/kotlin/com/saveourtool/diktat/kdoc/methods/MissingKdocOnFunctionExpected.kt",
    "content": "package test.paragraph2.kdoc\n\nclass Example {\n    /**\n * @return\n */\nfun hasNoChildren() = children.size == 0\n\n    /**\n * @return\n */\nfun getFirstChild() = children.elementAtOrNull(0)\n\n    @GetMapping(\"/projects\")\n    fun getProjects() = projectService.getProjects()\n}"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph2/kdoc/package/src/main/kotlin/com/saveourtool/diktat/kdoc/methods/MissingKdocOnFunctionTest.kt",
    "content": "package test.paragraph2.kdoc\n\nclass Example {\n    fun hasNoChildren() = children.size == 0\n\n    fun getFirstChild() = children.elementAtOrNull(0)\n\n    @GetMapping(\"/projects\")\n    fun getProjects() = projectService.getProjects()\n}"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph2/kdoc/package/src/main/kotlin/com/saveourtool/diktat/kdoc/methods/MissingKdocTested.kt",
    "content": "package com.saveourtool.diktat.kdoc.methods\n\nclass Example {\n    fun addInts(a: Int, b: Int): Int {\n        if (false) throw IllegalStateException()\n        return a + b\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph2/kdoc/package/src/main/kotlin/com/saveourtool/diktat/kdoc/methods/MissingKdocWithModifiersExpected.kt",
    "content": "package test.paragraph2.kdoc\n\nclass Example {\n    /**\n * @param a\n * @param b\n * @return\n * @throws IllegalStateException\n */\n@Deprecated(\"Use something else\")\n    internal fun addInts(a: Int, b: Int): Int {\n        if (false) throw IllegalStateException()\n        return a + b\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph2/kdoc/package/src/main/kotlin/com/saveourtool/diktat/kdoc/methods/MissingKdocWithModifiersTest.kt",
    "content": "package test.paragraph2.kdoc\n\nclass Example {\n    @Deprecated(\"Use something else\")\n    internal fun addInts(a: Int, b: Int): Int {\n        if (false) throw IllegalStateException()\n        return a + b\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph2/kdoc/package/src/main/kotlin/com/saveourtool/diktat/kdoc/methods/ParamTagInsertionExpected.kt",
    "content": "package com.saveourtool.diktat.kdoc.methods\n\nclass Example {\n    /**\n     * Lorem ipsum\n     * @param a\n     */\n    fun test1(a: Int): Unit { }\n\n    /**\n     * Lorem ipsum\n     * @param a\n     * @return integer value\n     */\n    fun test2(a: Int): Int = 0\n\n    /**\n     * Lorem ipsum\n     * @param a\n     * @throws IllegalStateException\n     */\n    fun test3(a: Int) {\n        throw IllegalStateException(\"dolor sit amet\")\n    }\n\n    /**\n     * Lorem ipsum\n     * @param a\n     * @return integer value\n     * @throws IllegalStateException\n     */\n    fun test4(a: Int): Int {\n        throw IllegalStateException(\"dolor sit amet\")\n        return 0\n    }\n\n    /**\n     * Lorem ipsum\n     * @param a\n     * @param b\n     * @return integer value\n     * @throws IllegalStateException\n     */\n    fun test5(a: Int, b: String): Int {\n        throw IllegalStateException(\"dolor sit amet\")\n        return 0\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph2/kdoc/package/src/main/kotlin/com/saveourtool/diktat/kdoc/methods/ParamTagInsertionTested.kt",
    "content": "package com.saveourtool.diktat.kdoc.methods\n\nclass Example {\n    /**\n     * Lorem ipsum\n     */\n    fun test1(a: Int): Unit { }\n\n    /**\n     * Lorem ipsum\n     * @return integer value\n     */\n    fun test2(a: Int): Int = 0\n\n    /**\n     * Lorem ipsum\n     * @throws IllegalStateException\n     */\n    fun test3(a: Int) {\n        throw IllegalStateException(\"dolor sit amet\")\n    }\n\n    /**\n     * Lorem ipsum\n     * @return integer value\n     * @throws IllegalStateException\n     */\n    fun test4(a: Int): Int {\n        throw IllegalStateException(\"dolor sit amet\")\n        return 0\n    }\n\n    /**\n     * Lorem ipsum\n     * @return integer value\n     * @throws IllegalStateException\n     */\n    fun test5(a: Int, b: String): Int {\n        throw IllegalStateException(\"dolor sit amet\")\n        return 0\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph2/kdoc/package/src/main/kotlin/com/saveourtool/diktat/kdoc/methods/ReturnTagInsertionExpected.kt",
    "content": "package com.saveourtool.diktat.kdoc.methods\n\nclass Example {\n    /**\n     * Lorem ipsum\n     * @return\n     */\n    fun test1(): Int = 0\n\n    /**\n     * Lorem ipsum\n     * @param a integer parameter\n     * @return\n     */\n    fun test2(a: Int): Int = 0\n\n    /**\n     * Lorem ipsum\n     * @return\n     * @throws IllegalStateException never\n     */\n    fun test3(): Int = 0\n\n    /**\n     * Lorem ipsum\n     * @param a integer parameter\n     * @return\n     * @throws IllegalStateException never\n     */\n    fun test4(a: Int): Int = 0\n\n    /**\n     * Lorem ipsum\n     * @throws IllegalStateException never\n     */\n    fun test5() = 0\n\n    /**\n     * Lorem ipsum\n     * @throws IllegalStateException never\n     */\n    fun A.test6() = 0\n}\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph2/kdoc/package/src/main/kotlin/com/saveourtool/diktat/kdoc/methods/ReturnTagInsertionTested.kt",
    "content": "package com.saveourtool.diktat.kdoc.methods\n\nclass Example {\n    /**\n     * Lorem ipsum\n     */\n    fun test1(): Int = 0\n\n    /**\n     * Lorem ipsum\n     * @param a integer parameter\n     */\n    fun test2(a: Int): Int = 0\n\n    /**\n     * Lorem ipsum\n     * @throws IllegalStateException never\n     */\n    fun test3(): Int = 0\n\n    /**\n     * Lorem ipsum\n     * @param a integer parameter\n     * @throws IllegalStateException never\n     */\n    fun test4(a: Int): Int = 0\n\n    /**\n     * Lorem ipsum\n     * @throws IllegalStateException never\n     */\n    fun test5() = 0\n\n    /**\n     * Lorem ipsum\n     * @throws IllegalStateException never\n     */\n    fun A.test6() = 0\n}\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph2/kdoc/package/src/main/kotlin/com/saveourtool/diktat/kdoc/methods/ThrowsTagInsertionExpected.kt",
    "content": "package com.saveourtool.diktat.kdoc.methods\n\nclass Example {\n    /**\n     * Lorem ipsum\n     * @throws IllegalStateException\n     */\n    fun test1(): Unit {\n        throw IllegalStateException(\"Lorem ipsum\")\n    }\n\n    /**\n     * Lorem ipsum\n     * @param a integer parameter\n     * @throws IllegalStateException\n     */\n    fun test2(a: Int): Unit  {\n        throw IllegalStateException(\"Lorem ipsum\")\n    }\n\n    /**\n     * Lorem ipsum\n     * @param a integer parameter\n     * @return integer value\n     * @throws IllegalStateException\n     */\n    fun test3(a: Int): Int  {\n        throw IllegalStateException(\"Lorem ipsum\")\n    }\n\n    /**\n     * Lorem ipsum\n     * @return integer value\n     * @throws IllegalStateException\n     */\n    fun test4(): Int  {\n        throw IllegalStateException(\"Lorem ipsum\")\n    }\n\n    /**\n     * Lorem ipsum\n     * @throws IllegalStateException\n     * @throws IllegalAccessException\n     */\n    fun test5() {\n        if (true) throw IllegalStateException(\"Lorem ipsum\")\n        else throw IllegalAccessException(\"Dolor sit amet\")\n    }\n\n    /**\n * @throws RuntimeException\n */\nfun test6() {\n        try {\n            foo()\n        } catch (_: NullPointerException) {\n            println(\"NPE!\")\n        } catch (e: RuntimeException) {\n            println(\"Whoops...\")\n            throw e\n        } catch (e: Error) {\n            val x = IllegalStateException()\n            println(\"Nothing to do here\")\n            throw x\n        }\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph2/kdoc/package/src/main/kotlin/com/saveourtool/diktat/kdoc/methods/ThrowsTagInsertionTested.kt",
    "content": "package com.saveourtool.diktat.kdoc.methods\n\nclass Example {\n    /**\n     * Lorem ipsum\n     */\n    fun test1(): Unit {\n        throw IllegalStateException(\"Lorem ipsum\")\n    }\n\n    /**\n     * Lorem ipsum\n     * @param a integer parameter\n     */\n    fun test2(a: Int): Unit  {\n        throw IllegalStateException(\"Lorem ipsum\")\n    }\n\n    /**\n     * Lorem ipsum\n     * @param a integer parameter\n     * @return integer value\n     */\n    fun test3(a: Int): Int  {\n        throw IllegalStateException(\"Lorem ipsum\")\n    }\n\n    /**\n     * Lorem ipsum\n     * @return integer value\n     */\n    fun test4(): Int  {\n        throw IllegalStateException(\"Lorem ipsum\")\n    }\n\n    /**\n     * Lorem ipsum\n     */\n    fun test5() {\n        if (true) throw IllegalStateException(\"Lorem ipsum\")\n        else throw IllegalAccessException(\"Dolor sit amet\")\n    }\n\n    fun test6() {\n        try {\n            foo()\n        } catch (_: NullPointerException) {\n            println(\"NPE!\")\n        } catch (e: RuntimeException) {\n            println(\"Whoops...\")\n            throw e\n        } catch (e: Error) {\n            val x = IllegalStateException()\n            println(\"Nothing to do here\")\n            throw x\n        }\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph3/annotations/AnnotationCommentExpected.kt",
    "content": "@Hello() // hello\n@Hi\nclass A {\n}\n@Foo\n/*  */ @Goo\n/*  */ @Qwe\n class AA {}\n/**  */ @Foo\n/** */ @Gg\n class Bb {}\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph3/annotations/AnnotationCommentTest.kt",
    "content": "@Hello() // hello\n@Hi\nclass A {\n}\n@Foo /*  */ @Goo /*  */ @Qwe class AA {}\n/**  */ @Foo /** */ @Gg class Bb {}\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph3/annotations/AnnotationConstructorSingleLineExpected.kt",
    "content": "package test.paragraph3.annotations\n\nclass SomeClass\n@Inject\n@SomeAnnotation\nconstructor() {\n\n    @ThirdAnnotation\n    @FourthAnnotation\n    fun someFunc(@Annotation var1: Int, @AnotherAnnotation var2: String) {\n\n    }\n}\n\nclass AnotherClass\n@Inject\n@SomeAnnotation\nconstructor() {\n\n}\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph3/annotations/AnnotationConstructorSingleLineTest.kt",
    "content": "package test.paragraph3.annotations\n\nclass SomeClass @Inject @SomeAnnotation\nconstructor() {\n\n    @ThirdAnnotation\n    @FourthAnnotation\n    fun someFunc(@Annotation var1: Int, @AnotherAnnotation var2: String) {\n\n    }\n}\n\nclass AnotherClass @Inject\n@SomeAnnotation\nconstructor() {\n\n}\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph3/annotations/AnnotationSingleLineExpected.kt",
    "content": "package test.paragraph3.annotations\n@SomeAnnotation\n@SecondAnnotation\nclass SomeClass @Inject constructor() {\n@ThirdAnnotation\n@FourthAnnotation\n fun someFunc(@Annotation var1: Int, @AnotherAnnotation var2: String) {\n\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph3/annotations/AnnotationSingleLineTest.kt",
    "content": "package test.paragraph3.annotations\n@SomeAnnotation @SecondAnnotation\nclass SomeClass @Inject constructor() {\n\n    @ThirdAnnotation @FourthAnnotation fun someFunc(@Annotation var1: Int, @AnotherAnnotation var2: String) {\n\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph3/blank_lines/CodeBlockWithBlankLinesExpected.kt",
    "content": "package test.paragraph3.blank_lines\n\nclass Example {\n    fun foo() {\n        bar()\n    }\n\n    fun bar() {\n        println()\n        println()\n    }\n}\n\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph3/blank_lines/CodeBlockWithBlankLinesTest.kt",
    "content": "package test.paragraph3.blank_lines\n\nclass Example {\n\n    fun foo() {\n\n        bar()\n\n    }\n\n    fun bar() {\n\n\n        println()\n        println()\n    }\n}\n\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph3/blank_lines/RedundantBlankLinesAtTheEndOfBlockExpected.kt",
    "content": "package test.paragraph3.blank_lines\n\nclass Example {\n    fun foo() {\n        bar()\n    }\n\n    fun bar() {\n        println()\n        println()\n    }\n}"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph3/blank_lines/RedundantBlankLinesAtTheEndOfBlockTest.kt",
    "content": "package test.paragraph3.blank_lines\n\nclass Example {\n    fun foo() {\n        bar()\n\n\n    }\n\n    fun bar() {\n        println()\n        println()\n\n\n\n    }\n\n\n}"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph3/blank_lines/RedundantBlankLinesExpected.kt",
    "content": "package test.paragraph3.blank_lines\n\nclass Example {\n    val foo = 0\n\n    fun bar() { }\n\n    fun foo() {\n        list.map {\n            bar()\n        }\n    }\n}\n\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph3/blank_lines/RedundantBlankLinesTest.kt",
    "content": "package test.paragraph3.blank_lines\n\n\nclass Example {\n\n\n    val foo = 0\n\n\n    fun bar() { }\n\n    fun foo() {\n        list.map {\n\n            bar()\n        }\n    }\n}\n\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph3/block_brace/ClassBracesExpected.kt",
    "content": "package test.paragraph3.block_brace\n\nclass A{\n    private val id = 10\n}\n\nclass B{\n    private val id = 10\n}\n\nclass C{\n    companion object{\n        private val id = 11\n}\n}\n\nclass D {\nval x = 0\n}\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph3/block_brace/ClassBracesTest.kt",
    "content": "package test.paragraph3.block_brace\n\nclass A{\n    private val id = 10\n}\n\nclass B{\n    private val id = 10}\n\nclass C{\n    companion object{\n        private val id = 11}\n}\n\nclass D {val x = 0}\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph3/block_brace/DoWhileBracesExpected.kt",
    "content": "package test.paragraph3.block_brace\n\nfun foo1() {\n    do {\n        println(\"hello\")\n    } while (x > 0)\n}\n\nfun foo2() {\n    do{\n        println(\"hello\")\n    } while (y > 0)\n}\n\nfun foo3() {\n    do {\n        println(\"hellp\")\n    }while (z > 0)\n}\n\nfun foo4() {\n    do {\n        println(\"hellp\")\n    } while (l > 0)\n}"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph3/block_brace/DoWhileBracesTest.kt",
    "content": "package test.paragraph3.block_brace\n\nfun foo1() {\n    do {\n        println(\"hello\")\n    } while (x > 0)\n}\n\nfun foo2() {\n    do{\n        println(\"hello\")\n    } while (y > 0)\n}\n\nfun foo3() {\n    do\n    {\n        println(\"hellp\")\n    }while (z > 0)\n}\n\nfun foo4() {\n    do\n    {\n        println(\"hellp\")\n    }\n    while (l > 0)\n}"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph3/block_brace/IfElseBracesExpected.kt",
    "content": "package test.paragraph3.block_brace\n\nfun foo1() {\n    if (x > 0) {\nfoo()\n} else {\nzoo()\n}\n}\n\nfun foo1(){\n    if (x < 0){\n        println(\"Helloo\")\n    }\n}\n\nfun foo2(){\n    if (x<0) {\nprintln(\"Hello\")\n    }\n}\n\nfun foo3(){\n    if (x == 5){\n        println(5)\n    } else if (x == 6)\n        println(6)\n    else\n        println(7)\n}\n\nfun foo4(){\n    if (x > 4){\n        println(4)\n    }else if (x < 4){\n        println(5)\n    }\n}\n\nfun foo() {\n    //comment1\n    // comment\nif(x) {\n        //comment2\n        foo()\n    }\n}"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph3/block_brace/IfElseBracesTest.kt",
    "content": "package test.paragraph3.block_brace\n\nfun foo1() {\n    if (x > 0) { foo() } else { zoo() }\n}\n\nfun foo1(){\n    if (x < 0){\n        println(\"Helloo\")\n    }\n}\n\nfun foo2(){\n    if (x<0) { println(\"Hello\")\n    }\n}\n\nfun foo3(){\n    if (x == 5){\n        println(5)\n    }\n    else if (x == 6)\n        println(6)\n    else\n        println(7)\n}\n\nfun foo4(){\n    if (x > 4){\n        println(4)\n    }else if (x < 4){\n        println(5)\n    }\n}\n\nfun foo() {\n    //comment1\n    if(x) // comment\n        {\n        //comment2\n        foo()\n    }\n}"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph3/block_brace/LoopsBracesExpected.kt",
    "content": "package test.paragraph3.block_brace\n\nfun foo(){\n    for (i in 1..100){\n        println(i)\n    }\n    for (i in 1..100) {\n        println(i)\n}\n\n    for (i in 1..100) {\nprintln(i)\n}\n}"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph3/block_brace/LoopsBracesTest.kt",
    "content": "package test.paragraph3.block_brace\n\nfun foo(){\n    for (i in 1..100){\n        println(i)\n    }\n    for (i in 1..100) {\n        println(i)}\n\n    for (i in 1..100) { println(i) }\n}"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph3/block_brace/TryBraceExpected.kt",
    "content": "package test.paragraph3.block_brace\n\nfun divideOrZero(numerator: Int, denominator: Int): Int {\n    try {\nreturn numerator / denominator\n    } catch (e: ArithmeticException) {\n        return 0\n    } catch (e: Exception) {\n        return 1\n    } finally {\n        println(\"Hello\")\n}\n}"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph3/block_brace/TryBraceTest.kt",
    "content": "package test.paragraph3.block_brace\n\nfun divideOrZero(numerator: Int, denominator: Int): Int {\n    try { return numerator / denominator\n    } catch (e: ArithmeticException) {\n        return 0\n    }\n    catch (e: Exception) {\n        return 1\n    }\n    finally {\n        println(\"Hello\") }\n}"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph3/block_brace/WhenBranchesExpected.kt",
    "content": "package test.paragraph3.block_brace\n\nfun foo(){\n    when(x){\n        1-> println(1)\n        else -> println(2)\n}\n\n    when(x) {\n1 -> println(1)\n        else -> println(2)\n}\n}"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph3/block_brace/WhenBranchesTest.kt",
    "content": "package test.paragraph3.block_brace\n\nfun foo(){\n    when(x){\n        1-> println(1)\n        else -> println(2)}\n\n    when(x)\n    {1 -> println(1)\n        else -> println(2)}\n}"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph3/boolean_expressions/BooleanExpressionsExpected.kt",
    "content": "package test.paragraph3.boolean_expressions\n\nfun foo() {\n    if (some != null && some == 6) {\n\n    }\n\n    if ((some != null || c > 2) && (a > 4 || b > 3)) {\n\n    }\n\n    if (a > 3 && b > 3) {\n\n    }\n\n    if (!a && !b) {}\n\n    if (c && !a && !b) {}\n}"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph3/boolean_expressions/BooleanExpressionsTest.kt",
    "content": "package test.paragraph3.boolean_expressions\n\nfun foo() {\n    if (some != null && some != null && some == 6) {\n\n    }\n\n    if ((some != null || c > 2) && (a > 4 || b > 3)) {\n\n    }\n\n    if (a > 3 && b > 3 && a > 3) {\n\n    }\n\n    if (!(a || b)) {}\n\n    if (!(a || b) && c) {}\n}"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph3/boolean_expressions/DistributiveLawExpected.kt",
    "content": "package test.paragraph3.boolean_expressions\n\nfun some() {\n    if (a > 5 && (b > 6 || c > 7)) {\n\n    }\n\n    if (a > 5 || (b > 6 && c > 7)) {\n\n    }\n\n    if (a > 5 || (b > 6 && c > 7 && d > 8)) {\n\n    }\n\n    if (a > 5 && (b > 6 || c > 7 || d > 8)) {\n\n    }\n\n    // Special case\n    if (a > 5 && (b > 6 || c > 7 || d > 8)) {\n\n    }\n\n    // long case\n    if (a > 5 && ((b > 6 && z > 3) || (c > 7 && y > 4) || (d > 8 && w > 5))) {\n\n    }\n\n    // long case #2.1\n    if (b > 6 && a > 5 && (z > 3 || c > 7 || w > 5)) {\n\n    }\n\n    // long case #2.2\n    if (b > 6 || a > 5 || (z > 3 && c > 7 && w > 5)) {\n\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph3/boolean_expressions/DistributiveLawTest.kt",
    "content": "package test.paragraph3.boolean_expressions\n\nfun some() {\n    if (a > 5 && b > 6 || c > 7 && a > 5) {\n\n    }\n\n    if ((a > 5 || b > 6) && (c > 7 || a > 5)) {\n\n    }\n\n    if ((a > 5 || b > 6) && (c > 7 || a > 5) && (a > 5 || d > 8)) {\n\n    }\n\n    if ((a > 5 && b > 6) || (c > 7 && a > 5) || (a > 5 && d > 8)) {\n\n    }\n\n    // Special case\n    if ((b > 6 && a > 5) || (c > 7 && a > 5) || (a > 5 && d > 8)) {\n\n    }\n\n    // long case\n    if ((b > 6 && a > 5 && z > 3) || (c > 7 && a > 5 && y > 4) || (a > 5 && d > 8 && w > 5)) {\n\n    }\n\n    // long case #2.1\n    if ((b > 6 && a > 5 && z > 3) || (c > 7 && a > 5 && b > 6) || (a > 5 && b > 6 && w > 5)) {\n\n    }\n\n    // long case #2.2\n    if ((b > 6 || a > 5 || z > 3) && (c > 7 || a > 5 || b > 6) && (a > 5 || b > 6 || w > 5)) {\n\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph3/boolean_expressions/ExpressionSimplificationExpected.kt",
    "content": "package test.paragraph3.boolean_expressions\n\nfun F.foo1() {\n    if (this.valueParameters[i].getFunctionName() != other.valueParameters[i].getFunctionName() || this.valueParameters[i].getFunctionType() == other.valueParameters[i].getFunctionType()\n    ) {\n        return false\n    }\n}\n\nfun F.foo2() {\n    if (this.valueParameters[i].getFunctionName() <= other.valueParameters[i].getFunctionName() || this.valueParameters[i].getFunctionType() >= other.valueParameters[i].getFunctionType()\n    ) {\n        return false\n    }\n}\n\nfun F.foo3() {\n    if (!(this.valueParameters[i].getFunctionName() xor other.valueParameters[i].getFunctionName()) || !(this.valueParameters[i].getFunctionType() xor other.valueParameters[i].getFunctionType())\n    ) {\n        return false\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph3/boolean_expressions/ExpressionSimplificationTest.kt",
    "content": "package test.paragraph3.boolean_expressions\n\nfun F.foo1() {\n    if (!(this.valueParameters[i].getFunctionName() == other.valueParameters[i].getFunctionName() &&\n                this.valueParameters[i].getFunctionType() != other.valueParameters[i].getFunctionType())\n    ) {\n        return false\n    }\n}\n\nfun F.foo2() {\n    if (!(this.valueParameters[i].getFunctionName() > other.valueParameters[i].getFunctionName() &&\n                this.valueParameters[i].getFunctionType() < other.valueParameters[i].getFunctionType())\n    ) {\n        return false\n    }\n}\n\nfun F.foo3() {\n    if (!(this.valueParameters[i].getFunctionName() xor other.valueParameters[i].getFunctionName() &&\n                this.valueParameters[i].getFunctionType() xor other.valueParameters[i].getFunctionType())\n    ) {\n        return false\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph3/boolean_expressions/NegativeExpressionExpected.kt",
    "content": "package test.paragraph3.boolean_expressions\n\nfun foo() {\n    if (bar) {\n    }\n    if (bar) {\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph3/boolean_expressions/NegativeExpressionTest.kt",
    "content": "package test.paragraph3.boolean_expressions\n\nfun foo() {\n    if (bar && (!isEmpty() || isEmpty())) {\n    }\n    if (bar && (isEmpty() || !isEmpty())) {\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph3/boolean_expressions/OrderIssueExpected.kt",
    "content": "package test.paragraph3.boolean_expressions\n\nfun foo() {\n    if (isB && isA && isC) {\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph3/boolean_expressions/OrderIssueTest.kt",
    "content": "package test.paragraph3.boolean_expressions\n\nfun foo() {\n    if (isB && isA && isC && (isEmpty() || !isEmpty())) {\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph3/boolean_expressions/SameExpressionsInConditionExpected.kt",
    "content": "fun foo() {\n    if (a) {}\n    if (a) {}\n    if (a) {}\n\n    return if (node is TomlKeyValueSimple) {\n        decodeValue().toString().toLowerCase() != \"null\"\n    } else {\n        true\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph3/boolean_expressions/SameExpressionsInConditionTest.kt",
    "content": "fun foo() {\n    if (a || a) {}\n    if (a && a) {}\n    if ((((a && a)))) {}\n\n    return if ((node is TomlKeyValueSimple) || (node is TomlKeyValueSimple)) {\n        decodeValue().toString().toLowerCase() != \"null\"\n    } else {\n        true\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph3/boolean_expressions/SubstitutionIssueExpected.kt",
    "content": "package test.paragraph3.boolean_expressions\n\nfun foo() {\n    if (isABC_A && isABC_B && isABC_C) {\n    }\n    if (isAdd && isAdded()) {\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph3/boolean_expressions/SubstitutionIssueTest.kt",
    "content": "package test.paragraph3.boolean_expressions\n\nfun foo() {\n    if (isABC_A && isABC_B && isABC_C && (isEmpty() || !isEmpty())) {\n    }\n    if (isAdd && isAdded() && (isEmpty() || !isEmpty())) {\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph3/braces/DoWhileBracesExpected.kt",
    "content": "package test.paragraph3.braces\n\nfun foo() {\n    do {\n    } while (condition)\n\n    do {\n    } while (condition)\n}"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph3/braces/DoWhileBracesTest.kt",
    "content": "package test.paragraph3.braces\n\nfun foo() {\n    do while (condition)\n\n    do\n    while (condition)\n}"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph3/braces/IfElseBraces1Expected.kt",
    "content": "package test.paragraph3.braces\n\nfun foo1() {\n    if (x > 0) {\n        foo()\n    } else {\n        bar()\n    }\n}\n\nfun foo2() {\n    if (x > 0) {\n        foo()\n    } else {\n        println(\"else\")\n        bar()\n    }\n}\n\nfun foo3() {\n    if (x > 0) {\n    } else {\n        bar()\n    }\n}\n\nfun foo4() {\n    if (x > 0) {\n    } else {\n    };\n}\n\nfun foo5() {\n    if (x > 0)\n        {\n        foo()\n    } else\n        {\n        bar()\n    }\n}\n\nfun foo6() {\n    if (x > 0) {\n        foo()\n    } else if (y > 0) {\n        abc()\n    } else {\n        bar()\n    }\n}\n\nfun foo7() {\n    if (x > 0)\n        {\n        foo()\n    } else if (y > 0)\n        {\n        abc()\n    } else\n        {\n        bar()\n    }\n}\n\nfun foo8() {\n    if (x > 0) {\n        if (y > 0) foo() else abc()\n    } else {\n        bar()\n    }\n}\n\nfun foo9() {\n    if (x > 0) {\n        foo()\n    } else if (y > 0) {\n        abc()\n    } else {\n        bar()\n    }\n}\n\nfun foo10() {\n    if (x > 0) {\n        foo()\n    } else if (z > 0) {\n        if (y > 0) abc() else qwe()\n    } else {\n        bar()\n    }\n}\n\nfun foo11() {\n    if (x > 0) else bar()\n}\n\nfun foo12() {\n    if (x > 0) {\n        foo()\n    } else {\n    };\n}\n\nfun foo13() {\n    if (x > 0) {\n    } else {\n    };\n}\n\nfun foo() {\n    if (a) {\n        bar()\n    } else b?.let {\n        baz()\n    }\n        ?: run {\n            qux()\n        }\n}\n\nfun foo() {\n    if (a) {\n        bar()\n    } else b.apply {\n        baz()\n    }\n}\n\nfun foo() {\n    if (a) {\n        bar()\n    } else {\n        baz(b.apply { id = 5 })\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph3/braces/IfElseBraces1Test.kt",
    "content": "package test.paragraph3.braces\n\nfun foo1() {\n    if (x > 0) foo()\n    else bar()\n}\n\nfun foo2() {\n    if (x > 0) foo()\n    else {\n        println(\"else\")\n        bar()\n    }\n}\n\nfun foo3() {\n    if (x > 0)\n    else {\n        bar()\n    }\n}\n\nfun foo4() {\n    if (x > 0)\n    else ;\n}\n\nfun foo5() {\n    if (x > 0)\n        foo()\n    else\n        bar()\n}\n\nfun foo6() {\n    if (x > 0) foo()\n    else if (y > 0) abc()\n    else bar()\n}\n\nfun foo7() {\n    if (x > 0)\n        foo()\n    else if (y > 0)\n        abc()\n    else\n        bar()\n}\n\nfun foo8() {\n    if (x > 0) if (y > 0) foo() else abc()\n    else bar()\n}\n\nfun foo9() {\n    if (x > 0) foo()\n    else if (y > 0) abc() else bar()\n}\n\nfun foo10() {\n    if (x > 0) foo()\n    else if (z > 0) if (y > 0) abc() else qwe()\n    else bar()\n}\n\nfun foo11() {\n    if (x > 0) else bar()\n}\n\nfun foo12() {\n    if (x > 0) foo() else ;\n}\n\nfun foo13() {\n    if (x > 0) else ;\n}\n\nfun foo() {\n    if (a) {\n        bar()\n    } else b?.let {\n        baz()\n    }\n        ?: run {\n            qux()\n        }\n}\n\nfun foo() {\n    if (a) {\n        bar()\n    } else b.apply {\n        baz()\n    }\n}\n\nfun foo() {\n    if (a) {\n        bar()\n    } else baz(b.apply { id = 5 })\n}\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph3/braces/IfElseBracesInsideScopeFunctionsExpected.kt",
    "content": "package test.paragraph3.braces\n\nfun foo1() {\n    str.apply {\n        if (x > 0) {\n            foo()\n        } else {\n            bar()\n        }\n    }\n}\n\nfun foo2() {\n    str.let { if (x > 0) { foo() }\n    else {\n     bar()\n }\n    }\n}\n\nfun foo3() {\n    str.run {\n        while (x > 0) {\n            if (x > 0) {\n                foo()\n            } else {\n                bar()\n            }\n        }\n    }\n}\n\nfun foo4() {\n    str.with { while (x > 0) {\n        if (x > 0) {\n            foo()\n        } else { bar() }\n    }\n    }\n}\n\nfun foo5() {\n    str.also {\n        while (x > 0) { if (x > 0) {\n     foo()\n } else {\n     bar()\n }\n        }\n    }\n}\n\nfun foo6() {\n    str.apply {\n        if (x > 0) {\n            foo()\n        } else if (y > 0) {\n            abc()\n        } else {\n            bar()\n        }\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph3/braces/IfElseBracesInsideScopeFunctionsTest.kt",
    "content": "package test.paragraph3.braces\n\nfun foo1() {\n    str.apply {\n        if (x > 0) foo()\n        else bar()\n    }\n}\n\nfun foo2() {\n    str.let { if (x > 0) { foo() }\n    else bar()\n    }\n}\n\nfun foo3() {\n    str.run {\n        while (x > 0) {\n            if (x > 0) foo()\n            else bar()\n        }\n    }\n}\n\nfun foo4() {\n    str.with { while (x > 0) {\n        if (x > 0) foo()\n        else { bar() }\n    }\n    }\n}\n\nfun foo5() {\n    str.also {\n        while (x > 0) { if (x > 0) foo()\n            else bar()\n        }\n    }\n}\n\nfun foo6() {\n    str.apply {\n        if (x > 0) foo()\n        else if (y > 0) abc()\n        else bar()\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph3/braces/LoopsBracesExpected.kt",
    "content": "package test.paragraph3.braces\n\nfun foo() {\n    for (i in 1..100) {\n        println(i)\n    }\n\n    while (condition) {\n        println(\"while\")\n    }\n\n    do {\n        println(\"do-while\")\n    } while (condition)\n}"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph3/braces/LoopsBracesInsideScopeFunctionsExpected.kt",
    "content": "package test.paragraph3.braces\n\nfun foo1() {\n    str.apply {\n        for (i in 1..100) {\n            println(i)\n        }\n    }\n}\n\nfun foo2() {\n    str.let { while (x > 0) {\n     println(i)\n }\n    }\n}\n\nfun foo3() {\n    str.run {\n        do {\n            println(i)\n        }\n        while (x > 0)\n    }\n}\n\nfun foo4() {\n    str.with { do {\n     println(i)\n }\n    while (x > 0)\n    }\n}\n\nfun foo5() {\n    str.also {\n        for (i in 1..100) {\n            while (x > 0)\n                {\n                println(i)\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph3/braces/LoopsBracesInsideScopeFunctionsTest.kt",
    "content": "package test.paragraph3.braces\n\nfun foo1() {\n    str.apply {\n        for (i in 1..100) println(i)\n    }\n}\n\nfun foo2() {\n    str.let { while (x > 0) println(i)\n    }\n}\n\nfun foo3() {\n    str.run {\n        do println(i)\n        while (x > 0)\n    }\n}\n\nfun foo4() {\n    str.with { do println(i)\n    while (x > 0)\n    }\n}\n\nfun foo5() {\n    str.also {\n        for (i in 1..100) {\n            while (x > 0)\n                println(i)\n        }\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph3/braces/LoopsBracesTest.kt",
    "content": "package test.paragraph3.braces\n\nfun foo() {\n    for (i in 1..100) println(i)\n\n    while (condition) println(\"while\")\n\n    do println(\"do-while\") while (condition)\n}"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph3/braces/WhenBranchesExpected.kt",
    "content": "package test.paragraph3.braces\n\nfun foo(x: Options) {\n    when (x) {\n        OPTION_1 -> println(1)\n        OPTION_2 -> println(2)\n        OPTION_3 -> println(3)\n        else -> {\n            println(\"error\")\n            throw IllegalStateException()\n        }\n    }\n}"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph3/braces/WhenBranchesTest.kt",
    "content": "package test.paragraph3.braces\n\nfun foo(x: Options) {\n    when (x) {\n        OPTION_1 -> { println(1) }\n        OPTION_2 -> {\n            println(2)\n        }\n        OPTION_3 -> println(3)\n        else -> {\n            println(\"error\")\n            throw IllegalStateException()\n        }\n    }\n}"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph3/collapse_if/CollapseIfStatementsExpected.kt",
    "content": "package test.paragraph3.collapse_if\n\n\nfun foo() {\n    if (true && true && true) {\n        val a = 6\n    }\n}\n\nfun foo() {\n    if (true) {\n        val someConstant = 5\n        if (true) {\n            doSomething()\n        }\n    }\n}\n\nfun foo() {\n    if (true && true) {\n\n        doSomething()\n    }\n}\n\nfun foo() {\n    if (true && true && true && true && true && true) {\n        doSomething()\n    }\n}\n\nfun foo() {\n\n}\n\nfun foo() {\n    fun1()\n    if (cond1) {\n        fun2()\n    } else if (cond2) {\n        fun3()\n    } else {\n        fun4()\n    }\n}\n\nfun foo() {\n    fun1()\n    if (cond1) {\n        fun2()\n    } else if (cond2) {\n        if (true) {\n            fun3()\n        }\n    } else {\n        fun4()\n    }\n}\n\nfun foo() {\n    fun1()\n    if (cond1) {\n        fun2()\n    } else if (cond2) {\n        if (true && true) {\n            fun3()\n        }\n    } else {\n        fun4()\n    }\n}\n\nfun foo() {\n    fun1()\n    if (cond1) {\n        fun2()\n    } else if (cond2) {\n        if (true && true) {\n            fun3()\n        }\n    } else {\n        fun4()\n        if (true && true) {\n            fun5()\n        }\n    }\n}\n\nfun foo() {\n    if (cond1 && (cond2 && cond3 || cond4)) {\n        firstAction()\n            secondAction()\n    }\n}\n\nfun foo() {\n    if (cond1 && cond2 && (cond3 || cond4)) {\n        someAction()\n    }\n}\n\nfun foo() {\n    if (cond1) {\n        if (cond2) {\n            firstAction()\n            secondAction()\n        } else {\n            firstAction()\n        }\n    } else {\n        secondAction()\n    }\n}\n\nfun foo () {\n    if (cond1) {\n        if (cond2) {\n            firstAction()\n            secondAction()\n        } else if (cond3) {\n            firstAction()\n        } else {\n            val a = 5\n        }\n    } else {\n        secondAction()\n    }\n}\n\nfun foo() {\n    if (cond1 && cond2) {\n        firstAction()\n            secondAction()\n    }\n    if (cond3) {\n        secondAction()\n    }\n}\n\nfun foo() {\n    if (cond1 && (cond2 || cond3)) {\n        firstAction()\n            secondAction()\n    }\n    if (cond4) {\n        secondAction()\n    }\n}\n\nfun foo () {\n    if (cond1) {\n        if (cond2 || cond3) {\n            firstAction()\n            secondAction()\n        }\n        if (cond4) {\n            secondAction()\n        }\n    }\n}\n\nfun foo() {\n    if (cond1) {\n        if (cond2) {\n            doSomething()\n        }\n        val a = 5\n    }\n}\n\nfun foo() {\n    if (true &&\n/*\n         Some Comments\n        */\n// More comments\ntrue) {\n        // comment 1\n            val a = 5\n            // comment 2\n            doSomething()\n        // comment 3\n    }\n}\n\nfun foo() {\n    if (true &&\n// Some\n// comments\ntrue) {\n        doSomething()\n    }\n}\n\nfun foo() {\n    // comment\n    if (cond1 &&\n/*\n         Some comments\n        */\n// More comments\n(cond2 || cond3)) {\n        doSomething()\n    }\n}\n\nfun foo() {\n    if (cond1 &&\n// comment\ncond2 &&\n// comment 2\ncond3) {\n        doSomething()\n    }\n}\n\nfun foo () {\n    if (true && true) {\n        doSomething()\n    }\n}\n\nfun foo () {\n     if (/*comment*/ true && true) {\n         doSomething()\n     }\n}\n\nfun foo () {\n    if (true /*comment*/ && true) {\n        doSomething()\n    }\n}\n\nfun foo () {\n    if (true && true /*comment*/) {\n        doSomething()\n    }\n}\n\nfun foo () {\n    if (true && (true || false) /*comment*/ && true /*comment*/) {\n        doSomething()\n    }\n}\n\nfun foo () {\n     if (true\n     /*comment\n     * more comments\n     */\n      && true /*comment 2*/) {\n         doSomething()\n     }\n}\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph3/collapse_if/CollapseIfStatementsTest.kt",
    "content": "package test.paragraph3.collapse_if\n\n\nfun foo() {\n    if (true) {\n        if (true) {\n            if (true) {\n                val a = 6\n            }\n        }\n    }\n}\n\nfun foo() {\n    if (true) {\n        val someConstant = 5\n        if (true) {\n            doSomething()\n        }\n    }\n}\n\nfun foo() {\n    if (true) {\n\n        if (true) {\n            doSomething()\n        }\n    }\n}\n\nfun foo() {\n    if (true) {\n        if (true) {\n            if (true) {\n                if (true) {\n                    if (true) {\n                        if (true) {\n                            doSomething()\n                        }\n                    }\n                }\n            }\n        }\n    }\n}\n\nfun foo() {\n\n}\n\nfun foo() {\n    fun1()\n    if (cond1) {\n        fun2()\n    } else if (cond2) {\n        fun3()\n    } else {\n        fun4()\n    }\n}\n\nfun foo() {\n    fun1()\n    if (cond1) {\n        fun2()\n    } else if (cond2) {\n        if (true) {\n            fun3()\n        }\n    } else {\n        fun4()\n    }\n}\n\nfun foo() {\n    fun1()\n    if (cond1) {\n        fun2()\n    } else if (cond2) {\n        if (true) {\n            if (true) {\n                fun3()\n            }\n        }\n    } else {\n        fun4()\n    }\n}\n\nfun foo() {\n    fun1()\n    if (cond1) {\n        fun2()\n    } else if (cond2) {\n        if (true) {\n            if (true) {\n                fun3()\n            }\n        }\n    } else {\n        fun4()\n        if (true) {\n            if (true) {\n                fun5()\n            }\n        }\n    }\n}\n\nfun foo() {\n    if (cond1) {\n        if (cond2 && cond3 || cond4) {\n            firstAction()\n            secondAction()\n        }\n    }\n}\n\nfun foo() {\n    if (cond1) {\n        if (cond2) {\n            if (cond3 || cond4) {\n                someAction()\n            }\n        }\n    }\n}\n\nfun foo() {\n    if (cond1) {\n        if (cond2) {\n            firstAction()\n            secondAction()\n        } else {\n            firstAction()\n        }\n    } else {\n        secondAction()\n    }\n}\n\nfun foo () {\n    if (cond1) {\n        if (cond2) {\n            firstAction()\n            secondAction()\n        } else if (cond3) {\n            firstAction()\n        } else {\n            val a = 5\n        }\n    } else {\n        secondAction()\n    }\n}\n\nfun foo() {\n    if (cond1) {\n        if (cond2) {\n            firstAction()\n            secondAction()\n        }\n    }\n    if (cond3) {\n        secondAction()\n    }\n}\n\nfun foo() {\n    if (cond1) {\n        if (cond2 || cond3) {\n            firstAction()\n            secondAction()\n        }\n    }\n    if (cond4) {\n        secondAction()\n    }\n}\n\nfun foo () {\n    if (cond1) {\n        if (cond2 || cond3) {\n            firstAction()\n            secondAction()\n        }\n        if (cond4) {\n            secondAction()\n        }\n    }\n}\n\nfun foo() {\n    if (cond1) {\n        if (cond2) {\n            doSomething()\n        }\n        val a = 5\n    }\n}\n\nfun foo() {\n    if (true) {\n        /*\n         Some Comments\n        */\n        // More comments\n        if (true) {\n            // comment 1\n            val a = 5\n            // comment 2\n            doSomething()\n        }\n        // comment 3\n    }\n}\n\nfun foo() {\n    if (true) {\n        // Some\n        // comments\n        if (true) {\n            doSomething()\n        }\n    }\n}\n\nfun foo() {\n    // comment\n    if (cond1) {\n        /*\n         Some comments\n        */\n        // More comments\n        if (cond2 || cond3) {\n            doSomething()\n        }\n    }\n}\n\nfun foo() {\n    if (cond1) {\n        // comment\n        if (cond2) {\n            // comment 2\n            if (cond3) {\n                doSomething()\n            }\n        }\n    }\n}\n\nfun foo () {\n    if (true) {\n        if (true) {doSomething()}\n    }\n}\n\nfun foo () {\n     if (/*comment*/ true) {\n         if (true) {\n             doSomething()\n         }\n     }\n}\n\nfun foo () {\n    if (true /*comment*/) {\n        if (true) {\n            doSomething()\n        }\n    }\n}\n\nfun foo () {\n    if (true) {\n        if (true /*comment*/) {\n            doSomething()\n        }\n    }\n}\n\nfun foo () {\n    if (true && (true || false) /*comment*/) {\n        if (true /*comment*/) {\n            doSomething()\n        }\n    }\n}\n\nfun foo () {\n     if (true\n     /*comment\n     * more comments\n     */\n     ) {\n         if (true /*comment 2*/) {\n             doSomething()\n         }\n     }\n}\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph3/else_expected/ElseInWhenExpected.kt",
    "content": "package test.paragraph3.else_expected\n\nenum class TestEnum {\n    ONE, TWO\n}\n\nfun testWhenExpression() {\n    val directoryType = TestEnum.ONE\n\n    when (directoryType) {\n        TestEnum.ONE -> \"d\"\n        TestEnum.TWO -> \"-\"\n    }\n\n    val noElse = when (directoryType) {\n        TestEnum.ONE -> \"d\"\n        TestEnum.TWO -> \"a\"\n    }\n\n    val v = 1\n    when (v) {\n        f(TestEnum.ONE) -> print(\"1\")\n        f(TestEnum.TWO) -> print(\"2\")\n    else -> {\n// this is a generated else block\n}}\n\n    val inLambda = {x: Int -> when(x) {\n        1 -> print(5)\n    }\n    }\n}\n\nsealed class Expr {\n    class Num(val value: Int) : Expr()\n    class Sum(val left: Expr, val right: Expr) : Expr()\n}\nfun eval(e: Expr): Int =\n    when (e) {\n        is Expr.Num -> e.value\n        is Expr.Sum -> eval(e.right) + eval(e.left)\n    }\n\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph3/else_expected/ElseInWhenTest.kt",
    "content": "package test.paragraph3.else_expected\n\nenum class TestEnum {\n    ONE, TWO\n}\n\nfun testWhenExpression() {\n    val directoryType = TestEnum.ONE\n\n    when (directoryType) {\n        TestEnum.ONE -> \"d\"\n        TestEnum.TWO -> \"-\"\n    }\n\n    val noElse = when (directoryType) {\n        TestEnum.ONE -> \"d\"\n        TestEnum.TWO -> \"a\"\n    }\n\n    val v = 1\n    when (v) {\n        f(TestEnum.ONE) -> print(\"1\")\n        f(TestEnum.TWO) -> print(\"2\")\n    }\n\n    val inLambda = {x: Int -> when(x) {\n        1 -> print(5)\n    }\n    }\n}\n\nsealed class Expr {\n    class Num(val value: Int) : Expr()\n    class Sum(val left: Expr, val right: Expr) : Expr()\n}\nfun eval(e: Expr): Int =\n    when (e) {\n        is Expr.Num -> e.value\n        is Expr.Sum -> eval(e.right) + eval(e.left)\n    }\n\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph3/empty_block/EmptyBlockExpected.kt",
    "content": "package test.paragraph3.empty_block\n\nfun foo () {\n    try {\n        doSome()\n    } catch (ex: Exception){\n}\n}\n\nfun goo () {\n    var x = 10\n    if (x == 10) return else println(10)\n    val y = listOf<Int>().map { }\n    for(x in 0..10) println(x)\n    while (x > 0)\n        --x\n}\n\nopen class RuleConfiguration(protected val config: Map<String, String>)\nobject EmptyConfiguration: RuleConfiguration(mapOf())\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph3/empty_block/EmptyBlockTest.kt",
    "content": "package test.paragraph3.empty_block\n\nfun foo () {\n    try {\n        doSome()\n    } catch (ex: Exception){}\n}\n\nfun goo () {\n    var x = 10\n    if (x == 10) return else println(10)\n    val y = listOf<Int>().map {\n\n    }\n    for(x in 0..10) println(x)\n    while (x > 0)\n        --x\n}\n\nopen class RuleConfiguration(protected val config: Map<String, String>)\nobject EmptyConfiguration: RuleConfiguration(mapOf())\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph3/enum_separated/EnumSeparatedExpected.kt",
    "content": "package test.paragraph3.enum_separated\n\nenum class ENUM {\n    A , B, C\n}\n\nenum class ENUM {\n    RED(0xFF0000),\n    GREEN(0x00FF00),\n    BLUE(0x0000FF), /*sdcsc*/\n;\n}\n\nenum class ENUM {\n    RED(0xFF0000),\n    GREEN(0x00FF00),\n    BLUE(0x0000FF),\n;\n}\n\nenum class ProtocolState {\n    WAITING {\n        override fun signal() = TALKING\n    },\n\n    TALKING {\n        override fun signal() = WAITING\n    },\n;\n    abstract fun signal(): ProtocolState\n}\n\nenum class ProtocolState {\n    WAITING {\n        val a = 10;\n    },\n\n    TALKING {\n        val b = 123;\n    },\n;\n    abstract fun signal(): ProtocolState\n}\n\nenum class Simple {\n    A, B, C\n}\n\nenum class SimpleWithFun {\n    A,\n B,\n C,\n;\n    fun foo() {}\n}\n\nenum class SimpleWithNewLine {\n    A,\n B,\n    C,\n;\n}\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph3/enum_separated/EnumSeparatedTest.kt",
    "content": "package test.paragraph3.enum_separated\n\nenum class ENUM {\n    A , B, C\n}\n\nenum class ENUM {\n    RED(0xFF0000),\n    GREEN(0x00FF00),\n    BLUE(0x0000FF) /*sdcsc*/\n}\n\nenum class ENUM {\n    RED(0xFF0000),\n    GREEN(0x00FF00),\n    BLUE(0x0000FF),;\n}\n\nenum class ProtocolState {\n    WAITING {\n        override fun signal() = TALKING\n    },\n\n    TALKING {\n        override fun signal() = WAITING\n    };\n    abstract fun signal(): ProtocolState\n}\n\nenum class ProtocolState {\n    WAITING {\n        val a = 10;\n    },\n\n    TALKING {\n        val b = 123;\n    };\n    abstract fun signal(): ProtocolState\n}\n\nenum class Simple {\n    A, B, C\n}\n\nenum class SimpleWithFun {\n    A, B, C;\n    fun foo() {}\n}\n\nenum class SimpleWithNewLine {\n    A, B,\n    C\n}\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph3/enum_separated/LastElementCommentExpected.kt",
    "content": "package test.paragraph3.enum_separated\n\nenum class Foo0 {\n    A,\n    B,\n    C,\n;\n}\n\nenum class Foo11 {\n    A,\n    B,\n    C, // some comment 11\n;\n}\n\nenum class Foo12 {\n    A,\n    B,\n    C,// some comment 12\n;\n}\n\nenum class Foo13 {\n    A,\n    B,\n    C,\n;// some comment 13\n}\n\nenum class Foo14 {\n    A,\n    B,\n    C,\n; // some comment 14\n}\n\nenum class Foo21 {\n    A,\n    B,\n    C, /* some comment 21 */\n;\n}\n\nenum class Foo22 {\n    A,\n    B,\n    C,/* some comment 22 */\n;\n}\n\nenum class Foo23 {\n    A,\n    B,\n    C,\n;/* some comment 23 */\n}\n\nenum class Foo24 {\n    A,\n    B,\n    C,\n; /* some comment 24 */\n}\n\nenum class Foo31 {\n    A,\n    B,\n    C,\n;\n /** some comment 31 */\n}\n\nenum class Foo32 {\n    A,\n    B,\n    C,\n;\n/** some comment 32 */\n}\n\nenum class Foo33 {\n    A,\n    B,\n    C,\n;\n/** some comment 33 */\n}\n\nenum class Foo34 {\n    A,\n    B,\n    C,\n;\n /** some comment 34 */\n}\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph3/enum_separated/LastElementCommentTest.kt",
    "content": "package test.paragraph3.enum_separated\n\nenum class Foo0 {\n    A,\n    B,\n    C\n}\n\nenum class Foo11 {\n    A,\n    B,\n    C // some comment 11\n}\n\nenum class Foo12 {\n    A,\n    B,\n    C// some comment 12\n}\n\nenum class Foo13 {\n    A,\n    B,\n    C;// some comment 13\n}\n\nenum class Foo14 {\n    A,\n    B,\n    C; // some comment 14\n}\n\nenum class Foo21 {\n    A,\n    B,\n    C /* some comment 21 */\n}\n\nenum class Foo22 {\n    A,\n    B,\n    C/* some comment 22 */\n}\n\nenum class Foo23 {\n    A,\n    B,\n    C;/* some comment 23 */\n}\n\nenum class Foo24 {\n    A,\n    B,\n    C; /* some comment 24 */\n}\n\nenum class Foo31 {\n    A,\n    B,\n    C /** some comment 31 */\n}\n\nenum class Foo32 {\n    A,\n    B,\n    C/** some comment 32 */\n}\n\nenum class Foo33 {\n    A,\n    B,\n    C;/** some comment 33 */\n}\n\nenum class Foo34 {\n    A,\n    B,\n    C; /** some comment 34 */\n}\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph3/file_structure/BlankLinesBetweenBlocksExpected.kt",
    "content": "/**\n * This is an example\n */\n\n@file:JvmName(\"Foo\")\n\npackage com.saveourtool.diktat.example\n\nimport com.saveourtool.diktat.Foo\n\nclass Example {\n    val y: Foo = Foo()\n}\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph3/file_structure/CompanionObjectWithCommentExpected.kt",
    "content": "package com.saveourtool.diktat\n\nimport io.micrometer.core.instrument.MeterRegistry\nimport org.springframework.stereotype.Component\n\n/**\n * @param meterRegistry\n * @param binRepository\n */\n@Component\nclass ActiveBinsMetric(meterRegistry: MeterRegistry, private val binRepository: BinRepository) {\n    companion object {\n        private const val EGG_4_5_BUCKET_LABEL = \"4-5\"\n        private const val EGG_3_BUCKET_LABEL = \"3\"\n        private const val EGG_OVER_10_BUCKET_LABEL = \"10+\"\n        private const val EGG_7_9_BUCKET_LABEL = \"7-9\"\n        private const val DELAY = 15000L\n\n        // 15s\n        private const val ACTIVE_BINS_METRIC_NAME = \"c.concurrent.bins\"\n        private const val NUMBER_OF_EGGS_LABEL = \"numberOfEggs\"\n        private const val ALL_ACTIVE_BINS_LABEL = \"total\"\n        private const val EGG_2_BUCKET_LABEL = \"2\"\n        private const val EGG_1_BUCKET_LABEL = \"1\"\n        private val numberOfEggsBuckets = setOf(\n            EGG_4_5_BUCKET_LABEL,\n            EGG_2_BUCKET_LABEL,\n            EGG_3_BUCKET_LABEL,\n            EGG_7_9_BUCKET_LABEL,\n            EGG_1_BUCKET_LABEL,\n            EGG_OVER_10_BUCKET_LABEL,\n            ALL_ACTIVE_BINS_LABEL)\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph3/file_structure/CompanionObjectWithCommentTest.kt",
    "content": "package com.saveourtool.diktat\n\nimport io.micrometer.core.instrument.MeterRegistry\nimport org.springframework.stereotype.Component\n\n/**\n * @param meterRegistry\n * @param binRepository\n */\n@Component\nclass ActiveBinsMetric(meterRegistry: MeterRegistry, private val binRepository: BinRepository) {\n    companion object {\n        private const val EGG_4_5_BUCKET_LABEL = \"4-5\"\n        private const val EGG_3_BUCKET_LABEL = \"3\"\n        private const val EGG_OVER_10_BUCKET_LABEL = \"10+\"\n        private const val EGG_7_9_BUCKET_LABEL = \"7-9\"\n        private const val DELAY = 15000L\n        // 15s\n        private const val ACTIVE_BINS_METRIC_NAME = \"c.concurrent.bins\"\n        private const val NUMBER_OF_EGGS_LABEL = \"numberOfEggs\"\n        private const val ALL_ACTIVE_BINS_LABEL = \"total\"\n        private const val EGG_2_BUCKET_LABEL = \"2\"\n        private const val EGG_1_BUCKET_LABEL = \"1\"\n        private val numberOfEggsBuckets = setOf(\n            EGG_4_5_BUCKET_LABEL,\n            EGG_2_BUCKET_LABEL,\n            EGG_3_BUCKET_LABEL,\n            EGG_7_9_BUCKET_LABEL,\n            EGG_1_BUCKET_LABEL,\n            EGG_OVER_10_BUCKET_LABEL,\n            ALL_ACTIVE_BINS_LABEL)\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph3/file_structure/CopyrightCommentPositionExpected.kt",
    "content": "/*\n * Copyright. All rights reserved.\n */\n\n@file:JvmName(\"Foo\")\n\npackage test.paragraph2.file_structure\n\nclass Example\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph3/file_structure/CopyrightCommentPositionTest.kt",
    "content": "@file:JvmName(\"Foo\")\n\n/*\n * Copyright. All rights reserved.\n */\n\npackage test.paragraph2.file_structure\n\nclass Example\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph3/file_structure/DeclarationsInClassOrderExpected.kt",
    "content": "package test.paragraph3.file_structure\n\nclass Example {\n    private val log = LoggerFactory.getLogger(Example.javaClass)\n\n    // lorem ipsum\n    private val FOO = 42\n    private val BAR = 43\n\n    /**\n     * Dolor sit amet\n     */\n    private val BAZ = 44\n    private lateinit var lateFoo: Int\n    init {\n        bar()\n    }\n\n    constructor(baz: Int)\n\n    fun foo() {\n        val nested = Nested()\n    }\n\n    class Nested {\n        val nestedFoo = 43\n    }\n\n    companion object {\n        private const val ZERO = 0\n        private var i = 0\n    }\n\n    class UnusedNested { }\n}\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph3/file_structure/DeclarationsInClassOrderTest.kt",
    "content": "package test.paragraph3.file_structure\n\nclass Example {\n    init {\n        bar()\n    }\n\n    companion object {\n        private const val ZERO = 0\n        private var i = 0\n    }\n\n    private lateinit var lateFoo: Int\n    // lorem ipsum\n    private val FOO = 42\n    private val log = LoggerFactory.getLogger(Example.javaClass)\n\n    class UnusedNested { }\n\n    constructor(baz: Int)\n\n    fun foo() {\n        val nested = Nested()\n    }\n\n    class Nested {\n        val nestedFoo = 43\n    }\n\n    private val BAR = 43\n    /**\n     * Dolor sit amet\n     */\n    private val BAZ = 44\n}\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph3/file_structure/DefaultPackageWithImportsExpected.kt",
    "content": "/*\n Copyright\n */\n\n@file:Suppress(\"\")\n\nimport baz.Baz\nimport foo.Bar\n\n/**\n * KDoc\n */\nclass Example{\n    val x: Bar = Bar()\n    val y: Baz = Baz()\n}"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph3/file_structure/DefaultPackageWithImportsTest.kt",
    "content": "@file:Suppress(\"\")\n/*\n Copyright\n */\nimport foo.Bar\nimport baz.Baz\n\n/**\n * KDoc\n */\nclass Example{\n    val x: Bar = Bar()\n    val y: Baz = Baz()\n}"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph3/file_structure/FileAnnotationExpected.kt",
    "content": "/**\n * This is an example\n */\n\n@file:JvmName(\"Foo\")\n\npackage test.paragraph2.file_structure\n\nclass Example\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph3/file_structure/FileAnnotationTest.kt",
    "content": "@file:JvmName(\"Foo\")\n/**\n * This is an example\n */\n\npackage test.paragraph2.file_structure\n\nclass Example\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph3/file_structure/HeaderKdocAfterPackageExpected.kt",
    "content": "/**\n * Header Kdoc\n */\n\npackage test.paragraph3.file_structure\n\nimport com.saveourtool.diktat.Bar\n\nclass A {\n    val a = Bar()\n}\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph3/file_structure/HeaderKdocAfterPackageTest.kt",
    "content": "package test.paragraph3.file_structure\n\n/**\n * Header Kdoc\n */\n\nimport com.saveourtool.diktat.Bar\n\nclass A {\n    val a = Bar()\n}\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph3/file_structure/LoggerOrderExpected.kt",
    "content": "package test.paragraph3.file_structure\n\nimport org.junit.platform.commons.logging.LoggerFactory\n\nclass LoggerOrderExample {\n    private val logger = getLogger(\"string template\")\n    private val logger = getLogger(\"\"\"string template\"\"\")\n    private val logger = getLogger(\"\"\"\nstring template\n\"\"\")\n    private val logger = getLogger(this.javaClass)\n    private val logger = getLogger(this.javaClass.name)\n    private val logger = getLogger(javaClass)\n    private val logger = getLogger(javaClass.name)\n    private val logger = getLogger(Foo::class.java)\n    private val logger = getLogger(Foo::class.java.name)\n    private val logger = getLogger(Foo::class)\n    private val logger = getLogger(Foo::class.name)\n    private val logger = getLogger<Foo>()\n    private val logger = getLogger({}.javaClass)\n    private val a = \"a\"\n    private val b = \"b\"\n    private val c = \"c\"\n    private val d = \"d\"\n    private val e = \"e\"\n    private val f = \"f\"\n    private val g = \"g\"\n    private val h = \"h\"\n    private val i = \"i\"\n    private val j = \"j\"\n    private val k = \"k\"\n    private val l = \"l\"\n    private val m = \"m\"\n    private val logger = LoggerFactory.getLogger(m)\n    private val n = \"n\"\n    private val logger = n.getLogger()\n    private val o = \"o\"\n    private val logger = o { get() }\n    private val p = \"p\"\n    private val logger = p::class.java.enclosingClass\n    private val q = \"q\"\n    private val logger = q::class.java\n    private val r = \"r\"\n    private val logger = r::javaClass\n    private val s = \"s\"\n    private val t = \"t\"\n    private val logger = getLogger(\"$s$t\")\n    private val u = \"u\"\n    private val v = \"v\"\n    private val w = \"w\"\n    private val x = \"x\"\n    private val y = \"y\"\n    private val z = \"z\"\n    private val logger = getLogger(\"$s$t$u$v$w\") { x + y + z }\n}\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph3/file_structure/LoggerOrderTest.kt",
    "content": "package test.paragraph3.file_structure\n\nimport org.junit.platform.commons.logging.LoggerFactory\n\nclass LoggerOrderExample {\n    private val logger = getLogger(\"string template\")\n    private val a = \"a\"\n    private val logger = getLogger(\"\"\"string template\"\"\")\n    private val b = \"b\"\n    private val logger = getLogger(\"\"\"\nstring template\n\"\"\")\n    private val c = \"c\"\n    private val logger = getLogger(this.javaClass)\n    private val d = \"d\"\n    private val logger = getLogger(this.javaClass.name)\n    private val e = \"e\"\n    private val logger = getLogger(javaClass)\n    private val f = \"f\"\n    private val logger = getLogger(javaClass.name)\n    private val g = \"g\"\n    private val logger = getLogger(Foo::class.java)\n    private val h = \"h\"\n    private val logger = getLogger(Foo::class.java.name)\n    private val i = \"i\"\n    private val logger = getLogger(Foo::class)\n    private val j = \"j\"\n    private val logger = getLogger(Foo::class.name)\n    private val k = \"k\"\n    private val logger = getLogger<Foo>()\n    private val l = \"l\"\n    private val logger = getLogger({}.javaClass)\n    private val m = \"m\"\n    private val logger = LoggerFactory.getLogger(m)\n    private val n = \"n\"\n    private val logger = n.getLogger()\n    private val o = \"o\"\n    private val logger = o { get() }\n    private val p = \"p\"\n    private val logger = p::class.java.enclosingClass\n    private val q = \"q\"\n    private val logger = q::class.java\n    private val r = \"r\"\n    private val logger = r::javaClass\n    private val s = \"s\"\n    private val t = \"t\"\n    private val logger = getLogger(\"$s$t\")\n    private val u = \"u\"\n    private val v = \"v\"\n    private val w = \"w\"\n    private val x = \"x\"\n    private val y = \"y\"\n    private val z = \"z\"\n    private val logger = getLogger(\"$s$t$u$v$w\") { x + y + z }\n}\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph3/file_structure/MissingBlankLinesBetweenBlocksTest.kt",
    "content": "/**\n * This is an example\n */\n@file:JvmName(\"Foo\")\npackage com.saveourtool.diktat.example\nimport com.saveourtool.diktat.Foo\nclass Example {\n    val y: Foo = Foo()\n}\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph3/file_structure/NoImportNoPackageExpected.kt",
    "content": "/*\n Copyright\n */\n\n@file:Suppress(\"\")\n\n/**\n * KDoc\n */\nclass Example"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph3/file_structure/NoImportNoPackageTest.kt",
    "content": "@file:Suppress(\"\")\n/*\n Copyright\n */\n\n/**\n * KDoc\n */\nclass Example"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph3/file_structure/OrderWithCommentExpected.kt",
    "content": "package test.paragraph3.file_structure\n\nclass Example {\n    companion object {\n        private val log = LoggerFactory.getLogger(Example.javaClass)\n        val q = 10\n\n        /*\n         * Dolor sit amet\n         */\n\n\n        /**\n         * hi\n         */\n        private val qq = 10\n}\n}"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph3/file_structure/OrderWithCommentTest.kt",
    "content": "package test.paragraph3.file_structure\n\nclass Example {\n    companion object {\n        val q = 10\n        private val log = LoggerFactory.getLogger(Example.javaClass)\n        /*\n         * Dolor sit amet\n         */\n\n\n        /**\n         * hi\n         */\n        private val qq = 10\n    }\n}"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph3/file_structure/OrderWithEnumsExpected.kt",
    "content": "enum class Enum {\n    FOO,\n    BAR,\n    ;\n    fun f() {}\n\n    companion object\n}"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph3/file_structure/OrderWithEnumsTest.kt",
    "content": "enum class Enum {\n    FOO,\n    BAR,\n    ;\n\n    companion object\n    fun f() {}\n}"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph3/file_structure/OtherCommentsExpected.kt",
    "content": "/**\n * This is an example\n */\n\n// some notes on this file\n// and some more\npackage com.saveourtool.diktat.example\n\nimport com.saveourtool.diktat.Foo\n\nclass Example {\n    val x: Foo = Foo()\n}\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph3/file_structure/OtherCommentsTest.kt",
    "content": "// some notes on this file\n// and some more\n/**\n * This is an example\n */\n\npackage com.saveourtool.diktat.example\n\nimport com.saveourtool.diktat.Foo\n\nclass Example {\n    val x: Foo = Foo()\n}\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph3/file_structure/RedundantBlankLinesBetweenBlocksTest.kt",
    "content": "/**\n * This is an example\n */\n\n\n@file:JvmName(\"Foo\")\n\n\n\n\npackage com.saveourtool.diktat.example\n\n\nimport com.saveourtool.diktat.Foo\n\n\n\n\n\n\n\nclass Example {\n    val y: Foo = Foo()\n}\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph3/file_structure/ReorderingImportsExpected.kt",
    "content": "package test.paragraph3.file_structure\n\n// lorem ipsum\nimport com.saveourtool.diktat.example.Bar\nimport com.saveourtool.diktat.example.Foo\nimport org.junit.jupiter.api.Test\n\nclass Example {\n    val x: Test = Test()\n    val y: Foo = Foo()\n    val z: Bar = Bar()\n}\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph3/file_structure/ReorderingImportsRecommendedExpected.kt",
    "content": "package test.paragraph3.file_structure\n\n// comment about java imports\nimport android.*\nimport androidx.*\nimport com.android.*\n\nimport com.saveourtool.*\nimport com.saveourtool.diktat.*\n\nimport com.fasterxml.jackson.databind.ObjectMapper\nimport com.google.common.base.CaseFormat\nimport io.gitlab.arturbosch.detekt.Detekt\nimport org.junit.jupiter.api.Assertions\nimport org.slf4j.Logger\nimport org.springframework.context.annotation.Bean\n\nimport java.io.IOException\nimport java.net.URL\nimport java.nio.charset.Charset\n\nimport kotlin.system.exitProcess\n\nclass Example {\n    val x = setOf<Object>(CaseFormat(), Detekt(), Assertions(), Logger(), Bean(), IOException(), URL(), Charset(), ObjectMapper())\n\n    fun Foo() {\n        while (true) {\n            exitProcess(1)\n        }\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph3/file_structure/ReorderingImportsRecommendedTest.kt",
    "content": "package test.paragraph3.file_structure\n\nimport com.android.*\nimport kotlin.system.exitProcess\n// comment about java imports\nimport java.io.IOException\nimport java.net.URL\nimport com.saveourtool.*\nimport com.fasterxml.jackson.databind.ObjectMapper\nimport android.*\nimport com.saveourtool.diktat.*\nimport org.junit.jupiter.api.Assertions\nimport androidx.*\nimport org.springframework.context.annotation.Bean\nimport com.google.common.base.CaseFormat\nimport java.nio.charset.Charset\nimport io.gitlab.arturbosch.detekt.Detekt\nimport org.slf4j.Logger\n\nclass Example {\n    val x = setOf<Object>(CaseFormat(), Detekt(), Assertions(), Logger(), Bean(), IOException(), URL(), Charset(), ObjectMapper())\n\n    fun Foo() {\n        while (true) {\n            exitProcess(1)\n        }\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph3/file_structure/ReorderingImportsTest.kt",
    "content": "package test.paragraph3.file_structure\n\nimport org.junit.jupiter.api.Test\nimport com.saveourtool.diktat.example.Foo\n// lorem ipsum\nimport com.saveourtool.diktat.example.Bar\nclass Example {\n    val x: Test = Test()\n    val y: Foo = Foo()\n    val z: Bar = Bar()\n}\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph3/file_structure/ScriptPackageDirectiveExpected.kts",
    "content": "@file:Suppress(\"DSL_SCOPE_VIOLATION\")// Without suppressing these, version catalog usage in `plugins` is marked as an error in IntelliJ:\n// https://youtrack.jetbrains.com/issue/KTIJ-19369\n\n\nplugins {\n    id(libs.plugins.kotlinJvm.get().pluginId)\n}\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph3/file_structure/ScriptPackageDirectiveTest.kts",
    "content": "// Without suppressing these, version catalog usage in `plugins` is marked as an error in IntelliJ:\n// https://youtrack.jetbrains.com/issue/KTIJ-19369\n@file:Suppress(\"DSL_SCOPE_VIOLATION\")\n\nplugins {\n    id(libs.plugins.kotlinJvm.get().pluginId)\n}\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph3/indentation/ConstructorExpected.kt",
    "content": "package test.paragraph3.indentation\n\nclass Example(protected val property1: Type1,\n              private val property2: Type2,\n              property3: Type3) {\n    constructor(property1: Type1,\n                property2: Type2) : this(property1,\n            property2, defaultValue)\n}\n\nsealed class SealedExample {\n    class Subclass1(val property1: Type1, val property2: Type) : SealedExample()\n    class Subclass(val property1: Type1, val property2: Type2,\n                   val property3: Type3, val property4: Type4) : SealedExample()\n}\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph3/indentation/ConstructorTest.kt",
    "content": "package test.paragraph3.indentation\n\nclass Example(protected val property1: Type1,\n              private val property2: Type2,\n              property3: Type3) {\n    constructor(property1: Type1,\n                property2: Type2) : this(property1,\n            property2, defaultValue)\n}\n\nsealed class SealedExample {\n    class Subclass1(val property1: Type1, val property2: Type) : SealedExample()\n    class Subclass(val property1: Type1, val property2: Type2,\n                   val property3: Type3, val property4: Type4) : SealedExample()\n}\n\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph3/indentation/IndentFullExpected.kt",
    "content": "package test.paragraph3.indentation\n\n@Deprecated(\"Use NewFoo instead\")\nclass Foo :\n    Comparable<Any>,\n    Appendable {\n    val test =\n            12\n\n    @Deprecated(\"Foo\")\n    fun foo1(\n            i1: Int,\n            i2: Int,\n            i3: Int\n    ): Int {\n        when (i1) {\n            is Number -> 0\n            else -> 1\n        }\n        if (i2 > 0 &&\n                i3 < 0\n        ) {\n            return 2\n        }\n        return 0\n    }\n\n    private fun foo2(): Int {\n        // todo: something\n        try {\n            return foo1(\n                    12,\n                    13,\n                    14\n            )\n        } catch (e: Exception) {\n            return 0\n        } finally {\n            if (true) {\n                return 1\n            } else {\n                return 2\n            }\n        }\n    }\n\n    fun foo3() {\n        Integer\n                .parseInt(\"32\").let {\n                    println(\"parsed $it\")\n                }\n    }\n\n    private val f =\n            { a: Int -> a * 2 }\n\n    fun longMethod(\n            @Named(\"param1\") param1: Int,\n            param2: String\n    ) {\n        @Deprecated val foo =\n                1\n    }\n\n    fun multilineMethod(\n            foo: String,\n            bar: String?,\n            x: Int?\n    ) {\n        foo.toUpperCase()\n                .trim()\n                .length\n        val barLen =\n                bar?.length ?: x\n                        ?: -1\n        if (foo.length > 0 &&\n                barLen > 0\n        ) {\n            println(\"> 0\")\n        }\n    }\n}\n\n@Deprecated\nval bar = 1\n\nenum class Enumeration {\n    A, B\n}\n\nfun veryLongExpressionBodyMethod() =\n        \"abc\"\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph3/indentation/IndentFullTest.kt",
    "content": "package test.paragraph3.indentation\n\n@Deprecated(\"Use NewFoo instead\")\nclass Foo :\nComparable<Any>,\nAppendable {\nval test =\n12\n\n@Deprecated(\"Foo\")\nfun foo1(\ni1: Int,\ni2: Int,\ni3: Int\n): Int {\nwhen (i1) {\nis Number -> 0\nelse -> 1\n}\nif (i2 > 0 &&\ni3 < 0\n) {\nreturn 2\n}\nreturn 0\n}\n\nprivate fun foo2(): Int {\n// todo: something\ntry {\nreturn foo1(\n12,\n13,\n14\n)\n} catch (e: Exception) {\nreturn 0\n} finally {\nif (true) {\nreturn 1\n} else {\nreturn 2\n}\n}\n}\n\nfun foo3() {\nInteger\n.parseInt(\"32\").let {\nprintln(\"parsed $it\")\n}\n}\n\nprivate val f =\n{ a: Int -> a * 2 }\n\nfun longMethod(\n@Named(\"param1\") param1: Int,\nparam2: String\n) {\n@Deprecated val foo =\n1\n}\n\nfun multilineMethod(\nfoo: String,\nbar: String?,\nx: Int?\n) {\nfoo.toUpperCase()\n.trim()\n.length\nval barLen =\nbar?.length ?: x\n?: -1\nif (foo.length > 0 &&\nbarLen > 0\n) {\nprintln(\"> 0\")\n}\n}\n}\n\n@Deprecated\nval bar = 1\n\nenum class Enumeration {\nA, B\n}\n\nfun veryLongExpressionBodyMethod() =\n\"abc\"\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph3/indentation/IndentationFull1Expected.kt",
    "content": "package test.paragraph3.indentation\n\ndata class Example(val field1: Type1,\n                   val field2: Type2) {\n    /**\n     * Lorem ipsum\n     * dolor sit amet\n     */\n    fun foo(\n            a: Int,\n            b: Int\n    ): Int {\n        return a + b\n    }\n\n    fun bar() {\n        for (i in 1..100)\n            println(i)\n\n        do\n            println()\n        while (condition)\n\n        for (i in 1..100) {\n            println(i)\n        }\n    }\n\n    fun baz() {\n        if (condition)\n            foobar()\n        else\n            foobaz()\n    }\n\n    fun some() {\n        val a = \"${\n            foo().bar()\n        }\"\n\n        val b = \"${baz().foo()}\"\n\n        val c = \"${\n            expression\n                .foo()\n                .bar()\n        }\"\n    }\n\n    val dockerFileAsText =\n            \"\"\"\n                    FROM $baseImage\n                COPY resources $resourcesPath\n                    RUN /bin/bash\n            \"\"\".trimIndent()\n\n    val some =\n            \"\"\"\n                          some $foo test\n                  $start another value\n            \"\"\".trimIndent()\n\n    val teeest =\n            \"\"\"\n                  some text $foo $bar another text\n            \"\"\".trimIndent()\n}\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph3/indentation/IndentationFull1Test.kt",
    "content": "package test.paragraph3.indentation\n\ndata class Example(val field1: Type1,\nval field2: Type2) {\n/**\n * Lorem ipsum\n * dolor sit amet\n */\nfun foo(\n    a: Int,\n    b: Int\n): Int {\n            return a + b\n    }\n\n    fun bar() {\n        for (i in 1..100)\n        println(i)\n\n        do\n        println()\n        while (condition)\n\n        for (i in 1..100) {\n        println(i)\n        }\n    }\n\n    fun baz() {\n        if (condition)\n        foobar()\n        else\n        foobaz()\n    }\n\n    fun some() {\n        val a = \"${\n        foo().bar()\n        }\"\n\n        val b = \"${baz().foo()}\"\n\n        val c = \"${\n        expression\n            .foo()\n            .bar()\n        }\"\n    }\n\n    val dockerFileAsText =\n                \"\"\"\n                        FROM $baseImage\n                    COPY resources $resourcesPath\n                        RUN /bin/bash\n                \"\"\".trimIndent()\n\n    val some =\n                  \"\"\"\n                                some $foo test\n                        $start another value\n                  \"\"\".trimIndent()\n\n    val teeest =\n                \"\"\"\n                      some text $foo $bar another text\n                \"\"\".trimIndent()\n}\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph3/indentation/IndentationParametersExpected.kt",
    "content": "package test.paragraph3.indentation\n\nclass Test(val param1: Type, val param2: Type,\n           val param3: Type)\n\nfun test(\n        param1: Type,\n        param2: Type, param3: Type\n) {\n    val test = Test(param1, param2,\n            param3)\n}\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph3/indentation/IndentationParametersTest.kt",
    "content": "package test.paragraph3.indentation\n\nclass Test(val param1: Type, val param2: Type,\nval param3: Type)\n\nfun test(\n    param1: Type,\n param2: Type, param3: Type\n) {\n    val test = Test(param1, param2,\n                    param3)\n}\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph3/long_line/LongBinaryExpressionExpected.kt",
    "content": "package test.paragraph3.long_line\n\nfun foo() {\n    val veryLongExpression =\n Methoooooooooooooooood() + 12345\n\n    val veryLongExpression =\n Methoooooooooooooooood() ?: null\n\n    val veryLongExpression = a.Methooooood() +\n b.field\n\n    val variable = someField.filter {\n it.elementType == KDOC\n }\n\n    // limit at the left side\n    val variable = a?.filter {\n it.elementType == KDOC\n } ?: null\n\n    // limit at the right side\n    val variable = bar?.filter { it.b == c }\n ?: null\n\n    // limit at the operation reference\n    val variable = field?.filter { bar == foo }\n ?: null\n\n    val variable = field?.filter { bar == foo }\n?: null\n\n    val variable = Methooood() * 2 + 12 + field\n ?: 123 + Methood().linelength\n\n    val variable = Methooood() * 2 + 12 + field\n?: 123 + Methood().linelength\n\n    val variable =\n Methoooooooooooooooooooooooooood()\n ?: \"some loooooong string\"\n\n    val variable = Methooooood()\n ?: \"some looong string\"\n\n    var headerKdoc = firstCodeNode.prevSibling {\n it.elementType == KDOC\n }\n ?: if (firstCodeNode == packageDirectiveNode) importsList?.prevSibling { it.elementType == KDOC } else null\n}\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph3/long_line/LongBinaryExpressionLastWordExpected.kt",
    "content": "package test.paragraph3.long_line\n\nval elem1 = (hasExplicitNotUnitReturnType || isFunWithExpressionBody && !hasExplicitUnitReturnType && hasNotExpressionBodyTypes) && !hasReturnKdoc &&\n !isReferenceExpressionWithSameName\n\nval elem2 = (hasExplicitNotUnitReturnType || isFunWithExpressionBody1 && !hasExplicitUnitReturnType && hasNotExpressionBodyTypes) && !hasReturnKdoc &&\n isReferenceExpressionWithSameName\n\nval elem3 = \"sdfghjkl;kjhgfdsdfghjkllkjhgfdsfghjkl;';lkiuytrdfghjklkjuhgfdsdfghnm,.lkjhgfdcvbnm,.lkjhgfdcvbnm,.lkjhgfdxcvbnm,lkjhgfdxcvbnm,lkgfdcvm\" +\n \"hgfjdgdsvfmg.k,gfdsgbh.gkhjhmhgdf\"\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph3/long_line/LongBinaryExpressionLastWordTest.kt",
    "content": "package test.paragraph3.long_line\n\nval elem1 = (hasExplicitNotUnitReturnType || isFunWithExpressionBody && !hasExplicitUnitReturnType && hasNotExpressionBodyTypes) && !hasReturnKdoc && !isReferenceExpressionWithSameName\n\nval elem2 = (hasExplicitNotUnitReturnType || isFunWithExpressionBody1 && !hasExplicitUnitReturnType && hasNotExpressionBodyTypes) && !hasReturnKdoc && isReferenceExpressionWithSameName\n\nval elem3 = \"sdfghjkl;kjhgfdsdfghjkllkjhgfdsfghjkl;';lkiuytrdfghjklkjuhgfdsdfghnm,.lkjhgfdcvbnm,.lkjhgfdcvbnm,.lkjhgfdxcvbnm,lkjhgfdxcvbnm,lkgfdcvm\" + \"hgfjdgdsvfmg.k,gfdsgbh.gkhjhmhgdf\"\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph3/long_line/LongBinaryExpressionTest.kt",
    "content": "package test.paragraph3.long_line\n\nfun foo() {\n    val veryLongExpression = Methoooooooooooooooood() + 12345\n\n    val veryLongExpression = Methoooooooooooooooood() ?: null\n\n    val veryLongExpression = a.Methooooood() + b.field\n\n    val variable = someField.filter { it.elementType == KDOC }\n\n    // limit at the left side\n    val variable = a?.filter { it.elementType == KDOC } ?: null\n\n    // limit at the right side\n    val variable = bar?.filter { it.b == c } ?: null\n\n    // limit at the operation reference\n    val variable = field?.filter { bar == foo } ?: null\n\n    val variable = field?.filter { bar == foo }?: null\n\n    val variable = Methooood() * 2 + 12 + field ?: 123 + Methood().linelength\n\n    val variable = Methooood() * 2 + 12 + field?: 123 + Methood().linelength\n\n    val variable = Methoooooooooooooooooooooooooood() ?: \"some loooooong string\"\n\n    val variable = Methooooood() ?: \"some looong string\"\n\n    var headerKdoc = firstCodeNode.prevSibling { it.elementType == KDOC } ?: if (firstCodeNode == packageDirectiveNode) importsList?.prevSibling { it.elementType == KDOC } else null\n}\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph3/long_line/LongComplexExpressionExpected.kt",
    "content": "package test.paragraph3.long_line\n\nfun foo(){\n    val attrs.disabled = (selfRole == Role.OWNER && isSelfRecord(props.selfUserInfo, user)) || !(selfRole.isHigherOrEqualThan(Role.OWNER) ||\n userRole.isLowerThan(selfRole))\n}\n\nval attrs.disabled = (selfRole == Role.OWNER && isSelfRecord(props.selfUserInfo, user)) || !(selfRole.isHigherOrEqualThan(Role.OWNER) ||\n userRole.isLowerThan(selfRole))\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph3/long_line/LongComplexExpressionTest.kt",
    "content": "package test.paragraph3.long_line\n\nfun foo(){\n    val attrs.disabled = (selfRole == Role.OWNER && isSelfRecord(props.selfUserInfo, user)) || !(selfRole.isHigherOrEqualThan(Role.OWNER) || userRole.isLowerThan(selfRole))\n}\n\nval attrs.disabled = (selfRole == Role.OWNER && isSelfRecord(props.selfUserInfo, user)) || !(selfRole.isHigherOrEqualThan(Role.OWNER) || userRole.isLowerThan(selfRole))\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph3/long_line/LongConditionInSmallFunctionExpected.kt",
    "content": "package test.paragraph3.long_line\n\nprivate fun isContainingRequiredPartOfCode(text: String): Boolean =\n            text.contains(\"val \", true) || text.contains(\"var \", true) || text.contains(\"=\", true) || (text.contains(\"{\", true) &&\n text.substringAfter(\"{\").contains(\"}\", true))\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph3/long_line/LongConditionInSmallFunctionTest.kt",
    "content": "package test.paragraph3.long_line\n\nprivate fun isContainingRequiredPartOfCode(text: String): Boolean =\n            text.contains(\"val \", true) || text.contains(\"var \", true) || text.contains(\"=\", true) || (text.contains(\"{\", true) && text.substringAfter(\"{\").contains(\"}\", true))\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph3/long_line/LongDotQualifiedExpressionExpected.kt",
    "content": "package test.paragraph3.long_line\n\nval G =\n ThisIsVeryyyyLooooonNameDooootQualifiedExpressioWithoutDot.lalalala.lalalal\n\nval A = This.Is.Veeeeryyyyyyy.Loooooong.Dot\n.Qualified.Expression\n\nval B = This?.Is?.Veeeeryyyyyyy?.Loooooong?.Dot\n?.Qualified?.Expression\n\nval C = This!!.Is!!.Veeeeryyyyyyy!!.Loooooong!!\n.Dot!!.Qualified!!.Expression\n\nval D = This.Is.Veeeeryyyyyyy.Loooooong.Dot\n    .Qualified.Expression\n\nval E = This?.Is?.Veeeeryyyyyyy?.Loooooong?.Dot\n    ?.Qualified?.Expression\n\nval F = This!!.Is!!.Veeeeryyyyyyy!!.Loooooong!!\n    .Dot!!.Qualified!!.Expression\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph3/long_line/LongDotQualifiedExpressionTest.kt",
    "content": "package test.paragraph3.long_line\n\nval G = ThisIsVeryyyyLooooonNameDooootQualifiedExpressioWithoutDot.lalalala.lalalal\n\nval A = This.Is.Veeeeryyyyyyy.Loooooong.Dot.Qualified.Expression\n\nval B = This?.Is?.Veeeeryyyyyyy?.Loooooong?.Dot?.Qualified?.Expression\n\nval C = This!!.Is!!.Veeeeryyyyyyy!!.Loooooong!!.Dot!!.Qualified!!.Expression\n\nval D = This.Is.Veeeeryyyyyyy.Loooooong.Dot\n    .Qualified.Expression\n\nval E = This?.Is?.Veeeeryyyyyyy?.Loooooong?.Dot\n    ?.Qualified?.Expression\n\nval F = This!!.Is!!.Veeeeryyyyyyy!!.Loooooong!!\n    .Dot!!.Qualified!!.Expression\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph3/long_line/LongExpressionInConditionExpected.kt",
    "content": "package test.paragraph3.long_line\n\nfun foo() {\n    val veryLooongStringName = \"ASDFGHJKL\"\n    val veryLooooooongConstIntName1 = 12345\n    val veryLooooooongConstIntName2 = 54321\n    var carry = 1\n    if (veryLooooooongConstIntName1 >\n veryLooooooongConstIntName2) {\n        carry++\n    } else if (veryLooooooongConstIntName2 >\n 123 * 12 && veryLooongStringName != \"asd\") {\n        carry+=2\n    } else if (1234 + 1235 + 1236 + 1237 + 1238 >\n 124 * 12) {\n        carry+=3\n    }\n}"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph3/long_line/LongExpressionInConditionTest.kt",
    "content": "package test.paragraph3.long_line\n\nfun foo() {\n    val veryLooongStringName = \"ASDFGHJKL\"\n    val veryLooooooongConstIntName1 = 12345\n    val veryLooooooongConstIntName2 = 54321\n    var carry = 1\n    if (veryLooooooongConstIntName1 > veryLooooooongConstIntName2) {\n        carry++\n    } else if (veryLooooooongConstIntName2 > 123 * 12 && veryLooongStringName != \"asd\") {\n        carry+=2\n    } else if (1234 + 1235 + 1236 + 1237 + 1238 > 124 * 12) {\n        carry+=3\n    }\n}"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph3/long_line/LongExpressionNoFixExpected.kt",
    "content": "package com.saveourtool.diktat.resources.paragraph3.longline\n\nclass veryLoooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong {\n    // looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooongggggggggggggggggggggggggg\n    //looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooongggggggggggggggggggggggggg\n    val s =\n \"d s d d d d ddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd\"\n}\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph3/long_line/LongExpressionNoFixTest.kt",
    "content": "package com.saveourtool.diktat.resources.paragraph3.longline\n\nclass veryLoooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong {\n    // looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooongggggggggggggggggggggggggg\n    //looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooongggggggggggggggggggggggggg\n    val s = \"d s d d d d ddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd\"\n}\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph3/long_line/LongInlineCommentsExpected.kt",
    "content": "package test.paragraph3.long_line\n\nfun foobar() {\n    foo(\n        // ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff\nbar()\n    )\n}\n\nfun foobar() {\n    foo(\n        //ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff\nbar()\n    )\n}\n\nfun foobar() {\n    foo(\n        // ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff\nbar(),\n        // uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu\nbaz()\n    )\n}\n\nfun foobar() {\n    // ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff\nbar()\n    // uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu\nbaz()\n}\n\nenum class SomeEnum {\n    // ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff\nFOO,\n    // ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff\nBAR,\n    // ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff\nBAZ,\n};\n\nfun foo() {\n    when (node.elementType) {\n        ElementType.CLASS, ElementType.FUN, ElementType.PROPERTY -> checkBlankLineAfterKdoc(node)\n        // ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff\nElementType.IF -> handleIfElse(node)\n        ElementType.EOL_COMMENT, ElementType.BLOCK_COMMENT -> handleEolAndBlockComments(node, configuration)\n        ElementType.KDOC ->\n handleKdocComments(node, configuration)\n        // ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff\nelse -> {\n            // this is a generated else block\n        }\n    }\n}\n\n// aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\nfun foo() {\n    // bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\nif (a) {\n        // cccccccccccccccccccccccccccccccccccccccccc\na()\n    // dddddddddddddddddddddddddddddddddddddddddd\n} else {\n        // eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee\nb()\n    // ffffffffffffffffffffffffffffffffffffffffff\n}\n// gggggggggggggggggggggggggggggggggggggggggggggggggggg\n}"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph3/long_line/LongInlineCommentsTest.kt",
    "content": "package test.paragraph3.long_line\n\nfun foobar() {\n    foo(\n        bar() // ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff\n    )\n}\n\nfun foobar() {\n    foo(\n        bar()//ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff\n    )\n}\n\nfun foobar() {\n    foo(\n        bar(), // ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff\n        baz()  // uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu\n    )\n}\n\nfun foobar() {\n    bar()  // ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff\n    baz()  // uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu\n}\n\nenum class SomeEnum {\n    FOO, // ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff\n    BAR, // ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff\n    BAZ, // ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff\n};\n\nfun foo() {\n    when (node.elementType) {\n        ElementType.CLASS, ElementType.FUN, ElementType.PROPERTY -> checkBlankLineAfterKdoc(node)\n        ElementType.IF -> handleIfElse(node) // ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff\n        ElementType.EOL_COMMENT, ElementType.BLOCK_COMMENT -> handleEolAndBlockComments(node, configuration)\n        ElementType.KDOC -> handleKdocComments(node, configuration)\n        else -> { // ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff\n            // this is a generated else block\n        }\n    }\n}\n\nfun foo() { // aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n    if (a) { // bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\n        a() // cccccccccccccccccccccccccccccccccccccccccc\n    } else { // dddddddddddddddddddddddddddddddddddddddddd\n        b() // eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee\n    } // ffffffffffffffffffffffffffffffffffffffffff\n} // gggggggggggggggggggggggggggggggggggggggggggggggggggg"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph3/long_line/LongLineAnnotationExpected.kt",
    "content": "package test.paragraph3.long_line\n\n@Query(\nvalue = \"select * from test inner join test_execution on test.id = test_execution.test_id and test_execution.st\",\n nativeQuery = true\n)\nfun retrieveBatches(limit: Int, offset: Int, executionId: Long): Some\n\n@Query(\nvalue = \"select * from test inner join test_execution on test.id = test_execution.test_id and test_execution.status = 'READY' and test_execution.test_suite_execution_id = ?3 limit ?1 offset ?2\",\n nativeQuery = true\n)\nfun some(limit: Int, offset: Int, executionId: Long): List<Test>\n\n@Query(value = \"select * from test inner joi\",\n nativeQuery = true)\nfun test(limit: Int, offset: Int, executionId: Long): List<Test>\n\n@Query(value = \"select * from test inner joibbb\",\n nativeQuery = true)\nfun cornerCase(limit: Int, offset: Int, executionId: Long): List<Test>\n\n@Query(\nvalue = \"select * from test inner join test_execution on test.id = test_execution.test_id and test_execution.status = 'READY' and test_execution.test_suite_execution_id = ?3 limit ?1 offset ?2\",\n nativeQuery = true\n)\nfun some(limit: Int, offset: Int, executionId: Long) =\n println(\n\"testtesttesttesttesttesttesttesttesttesttesttest\"\n)\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph3/long_line/LongLineAnnotationTest.kt",
    "content": "package test.paragraph3.long_line\n\n@Query(value = \"select * from test inner join test_execution on test.id = test_execution.test_id and test_execution.st\", nativeQuery = true)\nfun retrieveBatches(limit: Int, offset: Int, executionId: Long): Some\n\n@Query(value = \"select * from test inner join test_execution on test.id = test_execution.test_id and test_execution.status = 'READY' and test_execution.test_suite_execution_id = ?3 limit ?1 offset ?2\", nativeQuery = true)\nfun some(limit: Int, offset: Int, executionId: Long): List<Test>\n\n@Query(value = \"select * from test inner joi\", nativeQuery = true)\nfun test(limit: Int, offset: Int, executionId: Long): List<Test>\n\n@Query(value = \"select * from test inner joibbb\", nativeQuery = true)\nfun cornerCase(limit: Int, offset: Int, executionId: Long): List<Test>\n\n@Query(value = \"select * from test inner join test_execution on test.id = test_execution.test_id and test_execution.status = 'READY' and test_execution.test_suite_execution_id = ?3 limit ?1 offset ?2\", nativeQuery = true)\nfun some(limit: Int, offset: Int, executionId: Long) = println(\"testtesttesttesttesttesttesttesttesttesttesttest\")\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph3/long_line/LongLineCommentExpected.kt",
    "content": "package test.paragraph3.long_line\n\n// Hello World! This is a first part of comment.\n// This is a very long comment that cannot be\n// split\nfun foo() {\n    val namesList = listOf<String>(\"Jack\", \"Nick\")\n    namesList.forEach { name ->\n        if (name == \"Nick\") {\n            namesList.map {\n                // This is another comment\n// inside map\nit.subSequence(0, 1)\n                it.split(\"this is long regex\") // this comment start to the right of max length\n            }\n        }\n    }\n}\n\nfun goo() {\n    val ok = true // short comment\n    // h k comment looong comment\nval someLongFieldName = \"some string\"\n}\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph3/long_line/LongLineCommentExpected2.kt",
    "content": "/**\n * This rule checks if there is a backing property for field with property accessors, in case they don't use field keyword\n */\nclass ImplicitBackingPropertyRuleTest(configRules: List<RulesConfig>) {\n    private fun validateAccessors(node: ASTNode, propsWithBackSymbol: List<String>) {\n        // Comment, which should be moved\nval accessors =\n node.findAllDescendantsWithSpecificType(PROPERTY_ACCESSOR).filter { it.hasChildOfType(BLOCK) }\n        // Comment, which should be moved\nval accessors2 =\n            node.findAllDescendantsWithSpecificType(PROPERTY_ACCESSOR).filter { it.hasChildOfType(BLOCK) }\n        var accessors3 = node.findAllDescendantsWithSpecificType(PROPERTY_ACCESSOR).filter { it.hasChildOfType(BLOCK) }\n.forEach { handleGetAccessors(it, node, propsWithBackSymbol) }  // Comment, which shouldn't be moved\n        //                                 Comment, which should be moved\nvar accessors4 = node.findAllDescendantsWithSpecificType(PROPERTY_ACCESSOR).filter { it.hasChildOfType(BLOCK) }\n.forEach { handleGetAccessors(it, node, propsWithBackSymbol) }\n        var accessors5 = node.findAllDescendantsWithSpecificType(PROPERTY_ACCESSOR).filter { it.hasChildOfType(BLOCK) }\n.forEach { handleGetAccessors(it, node, propsWithBackSymbol) }  //                                                                      Comment, which shouldn't be moved\n        accessors.filter { it.hasChildOfType(GET_KEYWORD) }.forEach {\n handleGetAccessors(it, node, propsWithBackSymbol)\n }\n        accessors.filter { it.hasChildOfType(SET_KEYWORD) }.forEach {\n handleSetAccessors(it, node, propsWithBackSymbol)\n }\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph3/long_line/LongLineCommentTest.kt",
    "content": "package test.paragraph3.long_line\n\n// Hello World! This is a first part of comment. This is a very long comment that cannot be split\nfun foo() {\n    val namesList = listOf<String>(\"Jack\", \"Nick\")\n    namesList.forEach { name ->\n        if (name == \"Nick\") {\n            namesList.map {\n                it.subSequence(0, 1) // This is another comment inside map\n                it.split(\"this is long regex\") // this comment start to the right of max length\n            }\n        }\n    }\n}\n\nfun goo() {\n    val ok = true // short comment\n    val someLongFieldName = \"some string\" // h k comment looong comment\n}\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph3/long_line/LongLineCommentTest2.kt",
    "content": "/**\n * This rule checks if there is a backing property for field with property accessors, in case they don't use field keyword\n */\nclass ImplicitBackingPropertyRuleTest(configRules: List<RulesConfig>) {\n    private fun validateAccessors(node: ASTNode, propsWithBackSymbol: List<String>) {\n        val accessors = node.findAllDescendantsWithSpecificType(PROPERTY_ACCESSOR).filter { it.hasChildOfType(BLOCK) }  // Comment, which should be moved\n        val accessors2 =\n            node.findAllDescendantsWithSpecificType(PROPERTY_ACCESSOR).filter { it.hasChildOfType(BLOCK) }  // Comment, which should be moved\n        var accessors3 = node.findAllDescendantsWithSpecificType(PROPERTY_ACCESSOR).filter { it.hasChildOfType(BLOCK) }.forEach { handleGetAccessors(it, node, propsWithBackSymbol) }  // Comment, which shouldn't be moved\n        var accessors4 = node.findAllDescendantsWithSpecificType(PROPERTY_ACCESSOR).filter { it.hasChildOfType(BLOCK) }.forEach { handleGetAccessors(it, node, propsWithBackSymbol) }  //                                 Comment, which should be moved\n        var accessors5 = node.findAllDescendantsWithSpecificType(PROPERTY_ACCESSOR).filter { it.hasChildOfType(BLOCK) }.forEach { handleGetAccessors(it, node, propsWithBackSymbol) }  //                                                                      Comment, which shouldn't be moved\n        accessors.filter { it.hasChildOfType(GET_KEYWORD) }.forEach { handleGetAccessors(it, node, propsWithBackSymbol) }\n        accessors.filter { it.hasChildOfType(SET_KEYWORD) }.forEach { handleSetAccessors(it, node, propsWithBackSymbol) }\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph3/long_line/LongLineExpressionExpected.kt",
    "content": "package test.paragraph3.long_line\n\nfun foo() {\n    if (( x >  4365873654863745683)||\ny<238479283749238&&!isFoo()){}\n    if (( x >  4365873654863745683) ||\n y<238479283749238 && !isFoo()){}\n    if (q.text == \"dc\" && !IsFoo() ||\n x > 238479283749238 && y <                                   238479283749238 || g == \"text\"){}\n    if (q.text == \"dc\" && !IsFoo() ||\n x > 238479283749238 && y < 238479283749238 ||\n g == \"text\"){}\n    if (d == \"very long text\" &&\n gh == \"very long text\" || x > 238479283749238 ||\n y< 238479283749238){}\n    if (x ==\n 2384792837492387498728947289472987492){}\n    if (x == 972938473924535278492792738497){}\n    if (x == \"veery long text to split\" ||\n x == \"es\" || y == 123 || b > 12 && jh==234 ||\n h==54){}\n    if ((x > 0 ||\n y< 43658736548637456831231231223) ||\n (y < 123123132 && x > 123123132)){}\n    if ((x > 0 || ( y< 43658  )) &&\n (y < 123123132 && x > 123123132)){}\n    if (x > 0 || (y< 43658) && (y < 123123132 &&\n x > 123123132)){}\n    if (x > 0 || (y< 43658) && x!! ||\n (y < 123123)){}\n    if (x > 0 || (y< 43658) && (y < 123123) ||\n x!!){}\n    if (x > 0 || (y< 43658) && (y < 1231) ||\n (x!!)){}\n}\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph3/long_line/LongLineExpressionTest.kt",
    "content": "package test.paragraph3.long_line\n\nfun foo() {\n    if (( x >  4365873654863745683)||y<238479283749238&&!isFoo()){}\n    if (( x >  4365873654863745683) || y<238479283749238 && !isFoo()){}\n    if (q.text == \"dc\" && !IsFoo() || x > 238479283749238 && y <                                   238479283749238 || g == \"text\"){}\n    if (q.text == \"dc\" && !IsFoo() || x > 238479283749238 && y < 238479283749238 || g == \"text\"){}\n    if (d == \"very long text\" && gh == \"very long text\" || x > 238479283749238 || y< 238479283749238){}\n    if (x == 2384792837492387498728947289472987492){}\n    if (x == 972938473924535278492792738497){}\n    if (x == \"veery long text to split\" || x == \"es\" || y == 123 || b > 12 && jh==234 || h==54){}\n    if ((x > 0 || y< 43658736548637456831231231223) || (y < 123123132 && x > 123123132)){}\n    if ((x > 0 || ( y< 43658  )) && (y < 123123132 && x > 123123132)){}\n    if (x > 0 || (y< 43658) && (y < 123123132 && x > 123123132)){}\n    if (x > 0 || (y< 43658) && x!! || (y < 123123)){}\n    if (x > 0 || (y< 43658) && (y < 123123) || x!!){}\n    if (x > 0 || (y< 43658) && (y < 1231) || (x!!)){}\n}\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph3/long_line/LongLineFunExpected.kt",
    "content": "package test.paragraph3.long_line\n\nfun foo() = println(\n\"fhdbsfkhfbvsjfkvbhjdksfvhbhhjhjhjnaljfbkshvjdsjdnlvbdkhkjncdkljskbfvhdsjndlvfkbdhfjdncjsdcscsdcsdcsdcdd\"\n)\n\nfun foo () { println(\n\"fhdbsfkhfbvsjfkvbhjdksfvhbhhjhjhjnaljfbkshvjdsjdnlvbdkhkjncdkljskbfvhdsjndlvfkbdhfjdncjsdcscsdcsdcsdcdd\"\n) }"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph3/long_line/LongLineFunTest.kt",
    "content": "package test.paragraph3.long_line\n\nfun foo() = println(\"fhdbsfkhfbvsjfkvbhjdksfvhbhhjhjhjnaljfbkshvjdsjdnlvbdkhkjncdkljskbfvhdsjndlvfkbdhfjdncjsdcscsdcsdcsdcdd\")\n\nfun foo () { println(\"fhdbsfkhfbvsjfkvbhjdksfvhbhhjhjhjnaljfbkshvjdsjdnlvbdkhkjncdkljskbfvhdsjndlvfkbdhfjdncjsdcscsdcsdcsdcdd\") }"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph3/long_line/LongLineRValueExpected.kt",
    "content": "package test.paragraph3.long_line\n\nfun foo() {\n    val str = \"This is very long string that\" +\n\" should be split\"\n\n    fun foo() {\n        val veryLoooooooooooooooooongNamesList =\n listOf<String>(\"Jack\", \"Nick\")\n        veryLoooooooooooooooooongNamesList\n.forEach { name ->\n            if (name == \"Nick\") {\n                veryLoooooooooooooooooongNamesList\n.map { val str = \"This string shouldn't be split\"}\n                name.map { val str =\n \"This string should be split\" }\n            }\n        }\n    }\n\n    val longIntExpression = 12345 + 12345 +\n 12345 + 12345\n\n    val longIntExpression = (12345 + 12345 +\n 12345 + 12345)\n\n    val longIntExpression = (12345) + (12345) +\n (12345) + (12345)\n\n    val LongWithVar2 = \"very long\" +\n\" woooooordsdcsdcsdcsdc $variable\"\n\n    val longStringExpression = \"First part\" +\n \"second Part\"\n\n    val longStringExpression = \"First\" +\n \"second Part\"\n\n    val longStringExpression =\n \"First very long part\" + \"second Part\"\n\n    val longStringExpression2 =\n                   \"String starts at the line len limit\"\n\n    val veryLooooooooooooooooooooooooooooooongVal =\n \"text\"\n\n    val veryLongExpression = Method() + 12345 +\n baaar()\n\n    val veryLongExpression = Method() + baaar() +\n 12345\n}"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph3/long_line/LongLineRValueTest.kt",
    "content": "package test.paragraph3.long_line\n\nfun foo() {\n    val str = \"This is very long string that should be split\"\n\n    fun foo() {\n        val veryLoooooooooooooooooongNamesList = listOf<String>(\"Jack\", \"Nick\")\n        veryLoooooooooooooooooongNamesList.forEach { name ->\n            if (name == \"Nick\") {\n                veryLoooooooooooooooooongNamesList.map { val str = \"This string shouldn't be split\"}\n                name.map { val str = \"This string should be split\" }\n            }\n        }\n    }\n\n    val longIntExpression = 12345 + 12345 + 12345 + 12345\n\n    val longIntExpression = (12345 + 12345 + 12345 + 12345)\n\n    val longIntExpression = (12345) + (12345) + (12345) + (12345)\n\n    val LongWithVar2 = \"very long woooooordsdcsdcsdcsdc $variable\"\n\n    val longStringExpression = \"First part\" + \"second Part\"\n\n    val longStringExpression = \"First\" + \"second Part\"\n\n    val longStringExpression = \"First very long part\" + \"second Part\"\n\n    val longStringExpression2 =                   \"String starts at the line len limit\"\n\n    val veryLooooooooooooooooooooooooooooooongVal = \"text\"\n\n    val veryLongExpression = Method() + 12345 + baaar()\n\n    val veryLongExpression = Method() + baaar() + 12345\n}"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph3/long_line/LongShortRValueExpected.kt",
    "content": "package test.paragraph3.long_line\n\nval LongWithVar2 =\n \"${s + \"a\"} is a string\""
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph3/long_line/LongShortRValueTest.kt",
    "content": "package test.paragraph3.long_line\n\nval LongWithVar2 = \"${s + \"a\"} is a string\""
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph3/long_line/LongStringTemplateExpected.kt",
    "content": "object Observables {\n    // looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooongggggggggggggggggggggggggg\nval someCode = 15\n    // Some\n// looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong line\n    @Deprecated(\n\"New type inference algorithm in Kotlin 1.4 makes this method obsolete. Method will be removed in future RxKotlin release.\",\n        replaceWith = ReplaceWith(\"Observable.combineLatest(source1, source2, source3, source4, combineFunction)\",\n \"io.reactivex.Observable\"),\n        level = DeprecationLevel.WARNING\n)\n    @CheckReturnValue\n    @SchedulerSupport(SchedulerSupport.NONE)\n    inline fun <T1 : Any, T2 : Any, T3 : Any, T4 : Any, R : Any> combineLatest() {}\n}\n\nclass Foo() {\n\n    fun Fuu() {\n        logger.log(\n\"<-- ${response.code} ${ if (response.message.isEmpty()) \"skfnvkdjdfvd\" else \"dfjvndkjnbvif\" + response.message}\"\n)\n        logger.log(\n\"<-- ${response.code} ${ if (response.message.isEmpty()) \"skfnvsdcsdcscskdjdfvd\" else \"dfjvndsdcsdcsdcskjnbvif\" + response.message}\"\n)\n    }\n\n    val q = \"\"\"\n        <--${respodcnsee.ccode}${if (response.mesdscsage.isEmpty()) \"skfnvkdjeeeeeee\" else \"dfjvndksdcjnbvif\" +\n response.mecsssdcage}\n    \"\"\".trimIndent()\n\n    val w = \"\"\"\n        first line\n    veryy looooooooooooooooong second line didfuhyg djfghdf gjh erughdjf gbdpfughb ergen r fgdngjkdg e g s g d g\n d bd jk;g,e,r gd bnsfg e\n    \"\"\".trimIndent()\n\n    val e = \"\"\"\n        another line\n        <--${respodcnse.ccode}${if (response.mesdscsage.isEmpty()) \"skfnvkdjdsdcfvd\" else \"dfjvndksdcjnbvif\" +\n response.mecsssdcage}\n    \"\"\".trimIndent()\n\n    fun foo() {\n        val q = \"\"\"\n        re\n        ${\n            if (( x >\n  \"436587365486374568343658736548637456834365873654863745683436587365486374568343658736548637456834365873654863745683\") || y<238479283749238 && !isFoo()){}\n        }\n    \"\"\".trimIndent()\n    }\n\n    val stringName = \"This is long string template with binary expression. test should be up in level binary\" +\n\" expression and cannot split in operation reference and should be split this long string template\" + \"this string should be after operated reference\"\n}\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph3/long_line/LongStringTemplateTest.kt",
    "content": "object Observables {\n    val someCode = 15 // looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooongggggggggggggggggggggggggg\n    // Some looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong line\n    @Deprecated(\"New type inference algorithm in Kotlin 1.4 makes this method obsolete. Method will be removed in future RxKotlin release.\",\n        replaceWith = ReplaceWith(\"Observable.combineLatest(source1, source2, source3, source4, combineFunction)\", \"io.reactivex.Observable\"),\n        level = DeprecationLevel.WARNING)\n    @CheckReturnValue\n    @SchedulerSupport(SchedulerSupport.NONE)\n    inline fun <T1 : Any, T2 : Any, T3 : Any, T4 : Any, R : Any> combineLatest() {}\n}\n\nclass Foo() {\n\n    fun Fuu() {\n        logger.log(\"<-- ${response.code} ${ if (response.message.isEmpty()) \"skfnvkdjdfvd\" else \"dfjvndkjnbvif\" + response.message}\")\n        logger.log(\"<-- ${response.code} ${ if (response.message.isEmpty()) \"skfnvsdcsdcscskdjdfvd\" else \"dfjvndsdcsdcsdcskjnbvif\" + response.message}\")\n    }\n\n    val q = \"\"\"\n        <--${respodcnsee.ccode}${if (response.mesdscsage.isEmpty()) \"skfnvkdjeeeeeee\" else \"dfjvndksdcjnbvif\" + response.mecsssdcage}\n    \"\"\".trimIndent()\n\n    val w = \"\"\"\n        first line\n    veryy looooooooooooooooong second line didfuhyg djfghdf gjh erughdjf gbdpfughb ergen r fgdngjkdg e g s g d g d bd jk;g,e,r gd bnsfg e\n    \"\"\".trimIndent()\n\n    val e = \"\"\"\n        another line\n        <--${respodcnse.ccode}${if (response.mesdscsage.isEmpty()) \"skfnvkdjdsdcfvd\" else \"dfjvndksdcjnbvif\" + response.mecsssdcage}\n    \"\"\".trimIndent()\n\n    fun foo() {\n        val q = \"\"\"\n        re\n        ${\n            if (( x >  \"436587365486374568343658736548637456834365873654863745683436587365486374568343658736548637456834365873654863745683\") || y<238479283749238 && !isFoo()){}\n        }\n    \"\"\".trimIndent()\n    }\n\n    val stringName = \"This is long string template with binary expression. test should be up in level binary expression and cannot split in operation reference and should be split this long string template\" + \"this string should be after operated reference\"\n}\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph3/long_line/LongValueArgumentsListExpected.kt",
    "content": "package test.paragraph3.long_line\n\nval firstArgument = 1\nval secondArgument = 2\nval thirdArgument = 3\nval fourthArgument = 4\nval fifthArguments = 5\nval sixthArguments = 6\nval seventhArguments = 7\nval eighthArguments = 8\n\n// Many arguments in function\nval result1 = ManyParamInFunction(firstArgument,\n secondArgument, thirdArgument, fourthArgument,\n fifthArguments, sixthArguments, seventhArguments,\n eighthArguments)\n\n//\nval result2 = veryLongNameFun(firstArgument,\n secondArgument)\n\n// first argument cannot to be able to stay in\n// the first line\nval result3 = veryLongNameInFirstParam(\nfirstArgument, secondArgument, thirdArgument\n)\n\n// first argument cannot to be able to stay in\n// the first line\nval result4 = veryLongNameInFirstParam(\nfirstArgument\n)"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph3/long_line/LongValueArgumentsListTest.kt",
    "content": "package test.paragraph3.long_line\n\nval firstArgument = 1\nval secondArgument = 2\nval thirdArgument = 3\nval fourthArgument = 4\nval fifthArguments = 5\nval sixthArguments = 6\nval seventhArguments = 7\nval eighthArguments = 8\n\n// Many arguments in function\nval result1 = ManyParamInFunction(firstArgument, secondArgument, thirdArgument, fourthArgument, fifthArguments, sixthArguments, seventhArguments, eighthArguments)\n\n//\nval result2 = veryLongNameFun(firstArgument, secondArgument)\n\n// first argument cannot to be able to stay in the first line\nval result3 = veryLongNameInFirstParam(firstArgument, secondArgument, thirdArgument)\n\n// first argument cannot to be able to stay in the first line\nval result4 = veryLongNameInFirstParam(firstArgument)"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph3/long_numbers/LongNumericalValuesExpected.kt",
    "content": "package test.paragraph3.long_numbers\n\nfun foo() {\n    val oneMillion = 1_000_000\n    val ten = 10\n    val creditCardNumber = 1_234_567_890_123_456L\n    val socialSecurityNumber = 999_999_999L\n    val hexBytes = 0xFF_ECD_E5E\n    val bytes = 0b11_010_010_011_010_011_001_010_010_010_010\n    val flo = 192.312_341_341_344_355_345\n    val flo2 = 192.111_111_1\n    val flo3 = 1_924_345.145f\n    val flo4 = 1_924_345.145_111_11\n}\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph3/long_numbers/LongNumericalValuesTest.kt",
    "content": "package test.paragraph3.long_numbers\n\nfun foo() {\n    val oneMillion = 1000000\n    val ten = 10\n    val creditCardNumber = 1234567890123456L\n    val socialSecurityNumber = 999999999L\n    val hexBytes = 0xFFECDE5E\n    val bytes = 0b11010010011010011001010010010010\n    val flo = 192.312341341344355345\n    val flo2 = 192.111_111_1\n    val flo3 = 1924345.145f\n    val flo4 = 1924345.14511111\n}\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph3/multiple_modifiers/AnnotationExpected.kt",
    "content": "package test.paragraph3.multiple_modifiers\n\nimport org.jetbrains.kotlin.javax.inject.Inject\n\n@Annotation public final fun foo() {\n}\n\n@Annotation public fun foo() {\n}\n\n@Inject() @Suppress() public fun qwe() {\n}\n\n@Inject() @Suppress() public fun qwe() {\n}\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph3/multiple_modifiers/AnnotationTest.kt",
    "content": "package test.paragraph3.multiple_modifiers\n\nimport org.jetbrains.kotlin.javax.inject.Inject\n\npublic @Annotation final fun foo() {\n}\n\npublic @Annotation fun foo() {\n}\n\npublic @Suppress()@Inject() fun qwe() {\n}\n\npublic @Suppress() @Inject() fun qwe() {\n}\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph3/multiple_modifiers/ModifierExpected.kt",
    "content": "package test.paragraph3.multiple_modifiers\n\npublic enum class Q {}\n\nprotected data class Counter(val dayIndex: Int) {\n    suspend operator fun plus(increment: Int): Counter {\n        return Counter(dayIndex + increment)\n    }\n}\n\npublic final fun foo() {\n    protected open lateinit var a: List<ASTNode>\n}\n\npublic internal fun interface Factory {\n    public fun create(): List<Int>\n}\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph3/multiple_modifiers/ModifierTest.kt",
    "content": "package test.paragraph3.multiple_modifiers\n\nenum public class Q {}\n\ndata protected class Counter(val dayIndex: Int) {\n    operator suspend fun plus(increment: Int): Counter {\n        return Counter(dayIndex + increment)\n    }\n}\n\nfinal public fun foo() {\n    lateinit open protected var a: List<ASTNode>\n}\n\ninternal public fun interface Factory {\n    public fun create(): List<Int>\n}\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph3/newlines/ColonExpected.kt",
    "content": "package test.paragraph3.newlines\n\nfun foo(a: Int,\n        b: Int) { }\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph3/newlines/ColonTest.kt",
    "content": "package test.paragraph3.newlines\n\nfun foo(a\n        : Int,\n        b\n        : Int) { }\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph3/newlines/CommaExpected.kt",
    "content": "package test.paragraph3.newlines\n\nfun foo(a: Int,\n        b: Int) {\n    bar(a, b)\n}\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph3/newlines/CommaTest.kt",
    "content": "package test.paragraph3.newlines\n\nfun foo(a: Int\n        ,\n        b: Int) {\n    bar(a\n        , b)\n}\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph3/newlines/ExpressionBodyExpected.kt",
    "content": "package test.paragraph3.newlines\n\nfun foo(): String = \"lorem ipsum\"\n\nfun foo():String = \"lorem ipsum\"\n\nfun foo() : String = \"lorem ipsum\"\n\nfun recFoo(): String = \"lorem \" + recFoo()\n\nfun recFoo():String = \"lorem \" + recFoo()\n\nfun recFoo(): String = \"lorem \" + recFoo()\n\nfun foo() = \"lorem ipsum\"\n\nfun foo() = println(\"Logging\")"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph3/newlines/ExpressionBodyTest.kt",
    "content": "package test.paragraph3.newlines\n\nfun foo(): String {\n    return \"lorem ipsum\"\n}\n\nfun foo():String{\n    return \"lorem ipsum\"\n}\n\nfun foo() : String {\n    return \"lorem ipsum\"\n}\n\nfun recFoo(): String {\n    return \"lorem \" + recFoo()\n}\n\nfun recFoo():String {\n    return \"lorem \" + recFoo()\n}\n\nfun recFoo(): String{\n    return \"lorem \" + recFoo()\n}\n\nfun foo() = \"lorem ipsum\"\n\nfun foo() {\n    return println(\"Logging\")\n}"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph3/newlines/FunctionalStyleExpected.kt",
    "content": "package test.paragraph3.newlines\n\nfun foo(list: List<Bar>?) {\n    list!!\n.filterNotNull()\n.map { it.baz() }\n.firstOrNull {\n        it.condition()\n    }\n?.qux()\n            ?:foobar\n}\n\nfun bar(x :Int,y:Int) :Int = x+ y\n\nfun goo() {\n    x.map()\n.gro()\n            .gh()\n    t.map()\n.hg()\n.hg()\n    t\n            .map()\n            .filter()\n            .takefirst()\n    x\n            .map()\n            .filter()\n.hre()\n\n    t.responseBody!![0]\n.name\n}\n\nfun foo() {\n    foo\n ?: bar.baz()\n.qux()\n\n    foo\n ?: bar.baz()\n            .qux()\n}\n\nfun controlFlow(\ncode: CodeBlock,\n format: String,\n vararg args: Any?\n): CodeBlock =\n    CodeBlock.builder()\n.beginControlFlow(format, *args)\n.add(code)\n        .endControlFlow()\n.build()\n\nfun controlFlow(\ncode: CodeBlock,\n format: String,\n vararg args: Any?,\n): CodeBlock =\n    CodeBlock.builder()\n.beginControlFlow(format, *args)\n.add(code)\n        .endControlFlow()\n.build()\n\nfun foo(\na: Int,\n b: Int,\n c: Int\n): Int = 42\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph3/newlines/FunctionalStyleTest.kt",
    "content": "package test.paragraph3.newlines\n\nfun foo(list: List<Bar>?) {\n    list!!.filterNotNull().map { it.baz() }.firstOrNull {\n        it.condition()\n    }?.qux()\n            ?:\n            foobar\n}\n\nfun bar(x :Int,y:Int) :Int {\n    return   x+ y }\n\nfun goo() {\n    x.map().gro()\n            .gh()\n    t.map().hg().hg()\n    t\n            .map()\n            .filter()\n            .takefirst()\n    x\n            .map()\n            .filter().hre()\n\n    t.responseBody!![0].\n    name\n}\n\nfun foo() {\n    foo ?: bar.baz().qux()\n\n    foo ?: bar.baz()\n            .qux()\n}\n\nfun controlFlow(code: CodeBlock, format: String, vararg args: Any?): CodeBlock =\n    CodeBlock.builder().beginControlFlow(format, *args).add(code)\n        .endControlFlow().build()\n\nfun controlFlow(code: CodeBlock, format: String, vararg args: Any?,): CodeBlock =\n    CodeBlock.builder().beginControlFlow(format, *args).add(code)\n        .endControlFlow().build()\n\nfun foo(a: Int, b: Int, c: Int): Int = 42\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph3/newlines/LParExpected.kt",
    "content": "package test.paragraph3.newlines\n\nval a = Foo(0)"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph3/newlines/LParTest.kt",
    "content": "package test.paragraph3.newlines\n\nval a = Foo (0)"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph3/newlines/LambdaExpected.kt",
    "content": "package test.paragraph3.newlines\n\nclass Example {\n    val a = list.map { elem ->\n        foo(elem)\n    }\n    val b = list.map { elem: Type ->\n        foo(elem)\n    }\n    val c = list.map { elem ->\n bar(elem)\n    }\n    val d = list.map { elem: Type ->\n bar(elem)\n        foo(elem)\n    }\n    val e = list.map {\n bar(elem)\n        foo(elem)\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph3/newlines/LambdaTest.kt",
    "content": "package test.paragraph3.newlines\n\nclass Example {\n    val a = list.map {\n        elem ->\n        foo(elem)\n    }\n    val b = list.map { elem: Type\n        ->\n        foo(elem)\n    }\n    val c = list.map { elem\n        -> bar(elem)\n    }\n    val d = list.map { elem: Type -> bar(elem)\n        foo(elem)\n    }\n    val e = list.map { bar(elem)\n        foo(elem)\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph3/newlines/ListArgumentLambdaExpected.kt",
    "content": "package test.paragraph3.newlines\n\nclass Example {\n\n    fun foo() {\n        foldIndexed(\"#\") { index: Int, acc: String, pathPart: String ->\n        }\n    }\n\n    fun bar() {\n        foldIndexed(\"#\") { index, acc, pathPart ->\n        }\n    }\n\n}"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph3/newlines/ListArgumentLambdaTest.kt",
    "content": "package test.paragraph3.newlines\n\nclass Example {\n\n    fun foo() {\n        foldIndexed(\"#\") { index: Int, acc: String, pathPart: String ->\n        }\n    }\n\n    fun bar() {\n        foldIndexed(\"#\") { index, acc, pathPart ->\n        }\n    }\n\n}"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph3/newlines/LongDotQualifiedExpressionExpected.kt",
    "content": "package test.paragraph3.newlines\n\nval elem1 = firstArgumentDot()?.secondArgumentDot\n?.thirdArgumentDot\n?.fourthArgumentDot\n?.fifthArgumentDot\n?.sixthArgumentDot\n\n\nval elem2 = firstArgumentDot?.secondArgumentDot()\n?.thirdArgumentDot\n    ?.fourthArgumentDot\n?.fifthArgumentDot\n?.sixthArgumentDot\n\n\nval elem3 = firstArgumentDot?.secondArgumentDot?.thirdArgumentDot()\n?.fourthArgumentDot\n    ?.fifthArgumentDot\n?.sixthArgumentDot\n\n\nval elem4 = firstArgumentDot?.secondArgumentDot?.thirdArgumentDot + firstArgumentDot?.secondArgumentDot?.thirdArgumentDot?.fourthArgumentDot\n\n\nval elem5 = firstArgumentDot()!!.secondArgumentDot()!!\n.thirdArgumentDot!!\n.fourthArgumentDot!!\n.fifthArgumentDot!!\n.sixthArgumentDot()\n\n\nval elem6 = firstArgumentDot!!.secondArgumentDot!!.thirdArgumentDot()!!\n    .fourthArgumentDot!!\n.fifthArgumentDot()!!\n.sixthArgumentDot\n\n\nval elem7 = firstArgumentDot!!.secondArgumentDot()!!\n.thirdArgumentDot!!\n.fourthArgumentDot()!!\n    .fifthArgumentDot!!\n.sixthArgumentDot\n\n\nval elem8 = firstArgumentDot()!!.secondArgumentDot!!.thirdArgumentDot + firstArgumentDot!!.secondArgumentDot!!.thirdArgumentDot!!.fourthArgumentDot\n\n\nval elem9 = firstArgumentDot().secondArgumentDot\n.thirdArgumentDot()\n.fourthArgumentDot\n.fifthArgumentDot\n.sixthArgumentDot\n\n\nval elem10 = firstArgumentDot.secondArgumentDot()\n.thirdArgumentDot\n    .fourthArgumentDot\n.fifthArgumentDot()\n.sixthArgumentDot\n\n\nval elem11 = firstArgumentDot.secondArgumentDot.thirdArgumentDot()\n.fourthArgumentDot\n    .fifthArgumentDot\n.sixthArgumentDot\n\n\nval elem12 = firstArgumentDot.secondArgumentDot.thirdArgumentDot + firstArgumentDot.secondArgumentDot().thirdArgumentDot.fourthArgumentDot\n\n\nval elem13 = firstArgumentDot!!.secondArgumentDot?.thirdArgumentDot()\n.fourthArgumentDot!!\n.fifthArgumentDot()\n?.sixthArgumentDot\n\n\nval elem14 = firstArgumentDot.secondArgumentDot?.thirdArgumentDot()!!\n.fourthArgumentDot\n?.fifthArgumentDot\n.sixthArgumentDot\n\n\nval elem15 = firstArgumentDot?.secondArgumentDot!!.thirdArgumentDot.fourthArgumentDot()\n.fifthArgumentDot!!\n.sixthArgumentDot\n\n\nval elem16 = firstArgumentDot.secondArgumentDot.thirdArgumentDot.fourthArgumentDot.fifthArgumentDot.sixthArgumentDot\n\n\nval elem17 = firstArgumentDot!!.secondArgumentDot.thirdArgumentDot!!.fourthArgumentDot.fifthArgumentDot!!.sixthArgumentDot\n\n\nval elem18 = firstArgumentDot.secondArgumentDot?.thirdArgumentDot.fourthArgumentDot?.fifthArgumentDot.sixthArgumentDot\n\n\nprivate val holder: java.util.concurrent.atomic.AtomicReference<T> = java.util.concurrent.atomic.AtomicReference(valueToStore)\n\n\nprivate val holder: kotlin.native.concurrent.AtomicReference<T> = kotlin.native.concurrent.AtomicReference(valueToStore)\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph3/newlines/LongDotQualifiedExpressionTest.kt",
    "content": "package test.paragraph3.newlines\n\nval elem1 = firstArgumentDot()?.secondArgumentDot?.thirdArgumentDot?.fourthArgumentDot?.fifthArgumentDot?.sixthArgumentDot\n\n\nval elem2 = firstArgumentDot?.secondArgumentDot()?.thirdArgumentDot\n    ?.fourthArgumentDot?.fifthArgumentDot?.sixthArgumentDot\n\n\nval elem3 = firstArgumentDot?.secondArgumentDot?.thirdArgumentDot()?.fourthArgumentDot\n    ?.fifthArgumentDot?.sixthArgumentDot\n\n\nval elem4 = firstArgumentDot?.secondArgumentDot?.thirdArgumentDot + firstArgumentDot?.secondArgumentDot?.thirdArgumentDot?.fourthArgumentDot\n\n\nval elem5 = firstArgumentDot()!!.secondArgumentDot()!!.thirdArgumentDot!!.fourthArgumentDot!!.fifthArgumentDot!!.sixthArgumentDot()\n\n\nval elem6 = firstArgumentDot!!.secondArgumentDot!!.thirdArgumentDot()!!\n    .fourthArgumentDot!!.fifthArgumentDot()!!.sixthArgumentDot\n\n\nval elem7 = firstArgumentDot!!.secondArgumentDot()!!.thirdArgumentDot!!.fourthArgumentDot()!!\n    .fifthArgumentDot!!.sixthArgumentDot\n\n\nval elem8 = firstArgumentDot()!!.secondArgumentDot!!.thirdArgumentDot + firstArgumentDot!!.secondArgumentDot!!.thirdArgumentDot!!.fourthArgumentDot\n\n\nval elem9 = firstArgumentDot().secondArgumentDot.thirdArgumentDot().fourthArgumentDot.fifthArgumentDot.sixthArgumentDot\n\n\nval elem10 = firstArgumentDot.secondArgumentDot().thirdArgumentDot\n    .fourthArgumentDot.fifthArgumentDot().sixthArgumentDot\n\n\nval elem11 = firstArgumentDot.secondArgumentDot.thirdArgumentDot().fourthArgumentDot\n    .fifthArgumentDot.sixthArgumentDot\n\n\nval elem12 = firstArgumentDot.secondArgumentDot.thirdArgumentDot + firstArgumentDot.secondArgumentDot().thirdArgumentDot.fourthArgumentDot\n\n\nval elem13 = firstArgumentDot!!.secondArgumentDot?.thirdArgumentDot().fourthArgumentDot!!.fifthArgumentDot()?.sixthArgumentDot\n\n\nval elem14 = firstArgumentDot.secondArgumentDot?.thirdArgumentDot()!!.fourthArgumentDot?.fifthArgumentDot.sixthArgumentDot\n\n\nval elem15 = firstArgumentDot?.secondArgumentDot!!.thirdArgumentDot.fourthArgumentDot().fifthArgumentDot!!.sixthArgumentDot\n\n\nval elem16 = firstArgumentDot.secondArgumentDot.thirdArgumentDot.fourthArgumentDot.fifthArgumentDot.sixthArgumentDot\n\n\nval elem17 = firstArgumentDot!!.secondArgumentDot.thirdArgumentDot!!.fourthArgumentDot.fifthArgumentDot!!.sixthArgumentDot\n\n\nval elem18 = firstArgumentDot.secondArgumentDot?.thirdArgumentDot.fourthArgumentDot?.fifthArgumentDot.sixthArgumentDot\n\n\nprivate val holder: java.util.concurrent.atomic.AtomicReference<T> = java.util.concurrent.atomic.AtomicReference(valueToStore)\n\n\nprivate val holder: kotlin.native.concurrent.AtomicReference<T> = kotlin.native.concurrent.AtomicReference(valueToStore)\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph3/newlines/OneLineFunctionExpected.kt",
    "content": "package test.paragraph3.newlines\n\nclass Example {\n    fun doubleA(): Int = 2 * a\n}\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph3/newlines/OneLineFunctionTest.kt",
    "content": "package test.paragraph3.newlines\n\nclass Example {\n    fun doubleA(): Int {\n        return 2 * a\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph3/newlines/OperatorsExpected.kt",
    "content": "package test.paragraph3.newlines\n\nfun foo() {\n    val and = condition1&&\n condition2\n    val and2 = condition1&&\n            condition2\n    // this isn't an expression\n    val plus = x\n        + y\n\n    obj\n.foo()\n    obj\n            .foo()\n    obj\n?.foo()\n    obj\n ?:OBJ\n    obj\n::foo\n}\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph3/newlines/OperatorsTest.kt",
    "content": "package test.paragraph3.newlines\n\nfun foo() {\n    val and = condition1\n        && condition2\n    val and2 = condition1\n            &&\n            condition2\n    // this isn't an expression\n    val plus = x\n        + y\n\n    obj.\n        foo()\n    obj\n            .\n            foo()\n    obj?.\n        foo()\n    obj ?:\n        OBJ\n    obj::\n        foo\n}\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph3/newlines/ParameterListExpected.kt",
    "content": "package test.paragraph3.newlines\n\nfun bar(\narg1: Int,\n arg2: Int,\n arg3: Int\n) { }\n\nclass Foo :\nFooBase<Bar>(),\nBazInterface,\nBazSuperclass { }\n\nclass Foo(val arg1: Int, arg2: Int) { }\n\nclass Foo(\nval arg1: Int,\n arg2: Int,\n arg3: Int\n) {\n    constructor(\narg1: Int,\n arg2: String,\n arg3: String\n) : this(\narg1,\n 0,\n 0\n) { }\n}\n\nclass Foo(val arg1: Int,\n          var arg2: Int,\n          arg3: Int\n) { }\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph3/newlines/ParameterListTest.kt",
    "content": "package test.paragraph3.newlines\n\nfun bar(arg1: Int, arg2: Int, arg3: Int) { }\n\nclass Foo : FooBase<Bar>(), BazInterface, BazSuperclass { }\n\nclass Foo(val arg1: Int, arg2: Int) { }\n\nclass Foo(val arg1: Int, arg2: Int, arg3: Int) {\n    constructor(arg1: Int, arg2: String, arg3: String) : this(arg1, 0, 0) { }\n}\n\nclass Foo(val arg1: Int,\n          var arg2: Int,\n          arg3: Int) { }\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph3/newlines/SizeParameterListExpected.kt",
    "content": "package test.paragraph3.newlines\n\nfun foo(\na: Int,\n b: Int,\n c: Int\n) {\n    bar(a, b, c)\n}"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph3/newlines/SizeParameterListTest.kt",
    "content": "package test.paragraph3.newlines\n\nfun foo(a: Int, b: Int, c: Int) {\n    bar(a, b, c)\n}"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph3/newlines/SuperClassListOnTheSameLineExpected.kt",
    "content": "package test.paragraph3.newlines\n\nclass A<K : Any, P : Any, G : Any> :\nB<K>(),\nC<P>,\nD<G> {}\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph3/newlines/SuperClassListOnTheSameLineTest.kt",
    "content": "package test.paragraph3.newlines\n\nclass A<K : Any, P : Any, G : Any> : B<K>(),     C<P>, D<G> {}\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph3/nullable/CollectionExpected.kt",
    "content": "package test.paragraph3.nullable\n\nimport java.util.*\n\nclass A {\n    val a: List<Int> = emptyList()\n    val b: Iterable<Int> = emptyList()\n    val c: Map<Int, Int> = emptyMap()\n    val d: Array<Int> = emptyArray()\n    val e: Set<Int> = emptySet()\n    val f: Sequence<Int> = emptySequence()\n    val g: MutableList<Int> = mutableListOf()\n    val h: MutableMap<Int, Int> = mutableMapOf()\n    val i: MutableSet<Int> = mutableSetOf()\n    val j: LinkedList<Int> = LinkedList()\n    val k: LinkedHashMap<Int, Int> = LinkedHashMap()\n    val l: LinkedHashSet<Int> = LinkedHashSet()\n    val m: Queue<Int> = LinkedList()\n    val s: Iterator<Int>? = null\n}\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph3/nullable/CollectionTest.kt",
    "content": "package test.paragraph3.nullable\n\nimport java.util.*\n\nclass A {\n    val a: List<Int>? = null\n    val b: Iterable<Int>? = null\n    val c: Map<Int, Int>? = null\n    val d: Array<Int>? = null\n    val e: Set<Int>? = null\n    val f: Sequence<Int>? = null\n    val g: MutableList<Int>? = null\n    val h: MutableMap<Int, Int>? = null\n    val i: MutableSet<Int>? = null\n    val j: LinkedList<Int>? = null\n    val k: LinkedHashMap<Int, Int>? = null\n    val l: LinkedHashSet<Int>? = null\n    val m: Queue<Int>? = null\n    val s: Iterator<Int>? = null\n}\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph3/nullable/NullPrimitiveExpected.kt",
    "content": "package test.paragraph3.nullable\n\nclass A {\n    val a: Int = 0\n    val b: Double = 0.0\n    val c: Float = 0.0F\n    val d: Short = 0\n    val f: Byte = 0\n    val g: Long = 0L\n    val h: Char = ''\n}\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph3/nullable/NullPrimitiveTest.kt",
    "content": "package test.paragraph3.nullable\n\nclass A {\n    val a: Int? = null\n    val b: Double? = null\n    val c: Float? = null\n    val d: Short? = null\n    val f: Byte? = null\n    val g: Long? = null\n    val h: Char? = null\n}\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph3/preview_annotation/PreviewAnnotationMethodNameExpected.kt",
    "content": "package test.paragraph3.preview_annotation\n\n@Preview\nprivate fun BannerPreview() {}\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph3/preview_annotation/PreviewAnnotationMethodNameTest.kt",
    "content": "package test.paragraph3.preview_annotation\n\n@Preview\nprivate fun Banner() {}\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph3/preview_annotation/PreviewAnnotationPrivateModifierExpected.kt",
    "content": "package test.paragraph3.preview_annotation\n\n@Preview\n@Composable\nprivate fun BannerPreview1() {}\n\n@Preview\nprivate fun BannerPreview2() {}\n\n@Preview\nprivate fun BannerPreview3() {}\n\n@Preview\nprivate fun BannerPreview4() {}\n\n@Preview\nprivate fun BannerPreview5() {}\n\n@Preview\nfinal private fun BannerPreview6() {}\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph3/preview_annotation/PreviewAnnotationPrivateModifierTest.kt",
    "content": "package test.paragraph3.preview_annotation\n\n@Preview\n@Composable\npublic fun BannerPreview1() {}\n\n@Preview\nprotected fun BannerPreview2() {}\n\n@Preview\ninternal fun BannerPreview3() {}\n\n@Preview\nfun BannerPreview4() {}\n\n@Preview\nopen fun BannerPreview5() {}\n\n@Preview\nfinal fun BannerPreview6() {}\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph3/range/RangeToExpected.kt",
    "content": "package test.paragraph3.range\n\nfun foo() {\n    val num = 1\n    val w = num.rangeTo(num, num)\n    val q = 1..5\n    val e = num..num\n    if (1 in num..10) { }\n}\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph3/range/RangeToTest.kt",
    "content": "package test.paragraph3.range\n\nfun foo() {\n    val num = 1\n    val w = num.rangeTo(num, num)\n    val q = 1..5\n    val e = num.rangeTo(num)\n    if (1 in num.rangeTo(10)) { }\n}\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph3/range/RangeToUntilExpected.kt",
    "content": "package test.paragraph3.range\n\nclass A {\n    fun foo() {\n        for (i in 1..4) print(i)\n        for (i in 4 downTo 1) print(i)\n        for (i in 1 until 4) print(i)\n        for (i in 1..4 step 2) print(i)\n        for (i in 4 downTo 1 step 3) print(i)\n        if (6 in (1..10) && true) {}\n        for (i in 1 until (4)) print(i)\n        for (i in 1 until (b)) print(i)\n        for (i in ((1 until ((4))))) print(i)\n        for (i in 1..(4 - 2)) print(i)\n        for (i in 1..(b - 10)) print(i)\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph3/range/RangeToUntilTest.kt",
    "content": "package test.paragraph3.range\n\nclass A {\n    fun foo() {\n        for (i in 1..4) print(i)\n        for (i in 4 downTo 1) print(i)\n        for (i in 1 until 4) print(i)\n        for (i in 1..4 step 2) print(i)\n        for (i in 4 downTo 1 step 3) print(i)\n        if (6 in (1..10) && true) {}\n        for (i in 1..(4 - 1)) print(i)\n        for (i in 1..(b - 1)) print(i)\n        for (i in ((1 .. ((4 - 1))))) print(i)\n        for (i in 1..(4 - 2)) print(i)\n        for (i in 1..(b - 10)) print(i)\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph3/semicolons/SemicolonsExpected.kt",
    "content": "package test.paragraph3.newlines\n\nimport com.saveourtool.diktat.common.config.rules.RulesConfig\n\nenum class Example {\n    A,\n    B\n    ;\n\n    fun foo() {}\n    val a = 0\n    val b = if (condition) { bar(); baz()} else qux\n}\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph3/semicolons/SemicolonsTest.kt",
    "content": "package test.paragraph3.newlines;\n\nimport com.saveourtool.diktat.common.config.rules.RulesConfig;\n\nenum class Example {\n    A,\n    B\n    ;\n\n    fun foo() {};\n    val a = 0;\n    val b = if (condition) { bar(); baz()} else qux\n};\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph3/sort_error/ConstantsExpected.kt",
    "content": "package test.paragraph3.sort_error\n\nclass Test {\n    companion object {\n        private const val B = 4\n        private const val C = 4\n        private const val D = 4\n        private val SIMPLE_VALUE = listOf(IDENTIFIER, WHITE_SPACE, COMMA, SEMICOLON)\n    }\n}\n\nclass Test2 {\n    companion object {\n        private const val A = 4\n        private const val D = 4\n        private val SIMPLE_VALUE = listOf(IDENTIFIER, WHITE_SPACE, COMMA, SEMICOLON)\n        private const val B = 4\n    }\n}\n\nclass Test3 {\n    companion object\n}\n\nclass Test2 {\n    companion object {\n        private const val A = 4\n        private const val D = 4\n        private val SIMPLE_VALUE = listOf(IDENTIFIER, WHITE_SPACE, COMMA, SEMICOLON)\n        private const val Ba = 4\n        private const val Baa = 4\n        private const val Bb = 4\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph3/sort_error/ConstantsTest.kt",
    "content": "package test.paragraph3.sort_error\n\nclass Test {\n    companion object {\n        private const val D = 4\n        private const val C = 4\n        private const val B = 4\n        private val SIMPLE_VALUE = listOf(IDENTIFIER, WHITE_SPACE, COMMA, SEMICOLON)\n    }\n}\n\nclass Test2 {\n    companion object {\n        private const val A = 4\n        private const val D = 4\n        private val SIMPLE_VALUE = listOf(IDENTIFIER, WHITE_SPACE, COMMA, SEMICOLON)\n        private const val B = 4\n    }\n}\n\nclass Test3 {\n    companion object\n}\n\nclass Test2 {\n    companion object {\n        private const val A = 4\n        private const val D = 4\n        private val SIMPLE_VALUE = listOf(IDENTIFIER, WHITE_SPACE, COMMA, SEMICOLON)\n        private const val Baa = 4\n        private const val Ba = 4\n        private const val Bb = 4\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph3/sort_error/EnumSortExpected.kt",
    "content": "package test.paragraph3.sort_error\n\nenum class Alp {\n    BLUE(0x0000FF),\n    GREEN(0x00FF00),\n    RED(0xFF0000),\n;\n}\n\nenum class Warnings {\n    TALKING {\n        override fun signal() = TALKING\n    },\n    WAITING {\n        override fun signal() = TALKING\n    },\n;\n\n    abstract fun signal(): ProtocolState\n}\n\nenum class Warnings {\n    TALKING {\n        override fun signal() = TALKING\n    },\n    WAITING {\n        override fun signal() = TALKING\n    };\n\n    abstract fun signal(): ProtocolState\n}\n\nenum class Alp {\n    BLUE(0x0000FF),\n    GREEN(0x00FF00),\n    RED(0xFF0000),\n}\n\nenum class Alp {\n    BLUE(0x0000FF),\n    GREEN(0x00FF00),\n    RED(0xFF0000)\n;\n}\n\nenum class IssueType {\n    PROJECT_STRUCTURE, TESTS, VCS\n}\n\nenum class IssueType {\n    PROJECT_STRUCTURE,TESTS,VCS\n}\n\nenum class IssueType {\n    PROJECT_STRUCTURE, // comment\nTESTS,\nVCS\n}\n\nenum class IssueType {\n    PROJECT_STRUCTURE ,// comment\nTESTS,\nVCS\n}\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph3/sort_error/EnumSortTest.kt",
    "content": "package test.paragraph3.sort_error\n\nenum class Alp {\n    RED(0xFF0000),\n    GREEN(0x00FF00),\n    BLUE(0x0000FF),\n    ;\n}\n\nenum class Warnings {\n    WAITING {\n        override fun signal() = TALKING\n    },\n    TALKING {\n        override fun signal() = TALKING\n    },\n    ;\n\n    abstract fun signal(): ProtocolState\n}\n\nenum class Warnings {\n    WAITING {\n        override fun signal() = TALKING\n    },\n    TALKING {\n        override fun signal() = TALKING\n    };\n\n    abstract fun signal(): ProtocolState\n}\n\nenum class Alp {\n    RED(0xFF0000),\n    GREEN(0x00FF00),\n    BLUE(0x0000FF),\n}\n\nenum class Alp {\n    RED(0xFF0000),\n    GREEN(0x00FF00),\n    BLUE(0x0000FF)\n;\n}\n\nenum class IssueType {\n    VCS, PROJECT_STRUCTURE, TESTS\n}\n\nenum class IssueType {\n    VCS,PROJECT_STRUCTURE,TESTS\n}\n\nenum class IssueType {\n    VCS,PROJECT_STRUCTURE, // comment\n    TESTS\n}\n\nenum class IssueType {\n    VCS, TESTS, PROJECT_STRUCTURE // comment\n}\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph3/spaces/AnnotationExpected.kt",
    "content": "package test.paragraph3.spaces\n\n@Suppress(\"Text\") @Inject(\"sdc\")\nclass A {\n    @Suppress(\"AnotherText\")\n    fun foo() {\n\n    }\n\n    @RequestMapping(value = [\"/\"], method = [RequestMethod.GET])\n    fun goo() {\n\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph3/spaces/AnnotationTest.kt",
    "content": "package test.paragraph3.spaces\n\n@Suppress (\"Text\") @Inject(\"sdc\")\nclass A {\n    @Suppress (\"AnotherText\")\n    fun foo() {\n\n    }\n\n    @RequestMapping(value =[\"/\"], method = [RequestMethod.GET])\n    fun goo(){\n\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph3/spaces/BinaryOpExpected.kt",
    "content": "package test.paragraph3.spaces\n\nclass Example<T, R, Q> where T : UpperType, R : UpperType, Q : UpperType {\n    fun foo(t: T) = t + 1\n    fun foo2(t: T) = t + 1\n    fun foo3(t: T) = t + 1\n\n    fun bar() {\n        listOf<T>().map(this::foo)?.filter { elem -> predicate(elem) }!!\n        listOf<T>().map(this::foo)?.filter { elem -> predicate(elem) }!!.first()\n        listOf<T>().map(this::foo)?.filter { elem -> predicate(elem) }!!.first()\n    }\n}\n\nclass Test(@field:Anno val foo: Type,\n           @get:Anno val bar: Type,\n           @param:Anno val baz: Type) {\n    fun foo(): String = \"lorem\"\n    fun bar(): String = \"ipsum\"\n    fun baz(): String = \"dolor\"\n}\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph3/spaces/BinaryOpTest.kt",
    "content": "package test.paragraph3.spaces\n\nclass Example<T, R, Q> where T:UpperType, R: UpperType, Q :UpperType {\n    fun foo(t: T) = t+ 1\n    fun foo2(t: T) = t+1\n    fun foo3(t: T) = t +1\n\n    fun bar() {\n        listOf<T>() .map(this ::foo) ?.filter { elem ->predicate(elem) } !!\n        listOf<T>() . map(this :: foo) ?. filter { elem->predicate(elem) } !!.first()\n        listOf<T>(). map(this:: foo)?. filter { elem-> predicate(elem) } !!. first()\n    }\n}\n\nclass Test(@field: Anno val foo: Type,\n           @get :Anno val bar : Type,\n           @param : Anno val baz :Type) {\n    fun foo(): String = \"lorem\"\n    fun bar() : String = \"ipsum\"\n    fun baz() :String = \"dolor\"\n}\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph3/spaces/BracesLambdaSpacesExpected.kt",
    "content": "package test.paragraph3.spaces\n\nclass Some {\n    fun foo() {\n        list.map { it.text }\n    }\n}\n\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph3/spaces/BracesLambdaSpacesTest.kt",
    "content": "package test.paragraph3.spaces\n\nclass Some {\n    fun foo() {\n        list.map {it.text}\n    }\n}\n\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph3/spaces/EolSpacesExpected.kt",
    "content": "package test.paragraph3.spaces\n\nclass Example {\n    fun foo() {\n        bar()\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph3/spaces/EolSpacesTest.kt",
    "content": "package test.paragraph3.spaces\n\nclass Example {    \n    fun foo() {    \n        bar()    \n    }    \n}    \n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph3/spaces/EqualsExpected.kt",
    "content": "package test.paragraph3.spaces\n\nclass A {\n    fun foo() {\n        val q = 10\n        var w = q\n        w = 4\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph3/spaces/EqualsTest.kt",
    "content": "package test.paragraph3.spaces\n\nclass A {\n    fun foo() {\n        val q=10\n        var w = q\n        w=4\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph3/spaces/LBraceAfterKeywordExpected.kt",
    "content": "package test.paragraph3.spaces\n\nclass Example {\n    fun foo() {\n        if (condition) { }\n        else {}\n        try { }\n        finally { }\n    }\n\n    fun bar() {\n        if (condition) { }\n        else {}\n        try { }\n        finally { }\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph3/spaces/LBraceAfterKeywordTest.kt",
    "content": "package test.paragraph3.spaces\n\nclass Example {\n    fun foo() {\n        if (condition) { }\n        else{}\n        try{ }\n        finally{ }\n    }\n\n    fun bar() {\n        if (condition) { }\n        else  {}\n        try   { }\n        finally   { }\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph3/spaces/LambdaAsArgumentExpected.kt",
    "content": "package test.paragraph3.spaces\n\nfun foo(a: (Int) -> Int, b: Int) {\n    foo({ x: Int -> x }, 5)\n}\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph3/spaces/LambdaAsArgumentTest.kt",
    "content": "package test.paragraph3.spaces\n\nfun foo(a: (Int) -> Int, b: Int) {\n    foo( { x: Int -> x }, 5)\n}\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph3/spaces/LbraceExpected.kt",
    "content": "package test.paragraph3.spaces\n\nclass Example {\n    fun foo() {\n        list.run {\n            map { bar(it) }\n        }\n        lister.map { \"${ruleId}\" }\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph3/spaces/LbraceTest.kt",
    "content": "package test.paragraph3.spaces\n\nclass Example{\n    fun foo()  {\n        list.run{\n            map  { bar(it) }\n        }\n        lister.map { \"${ruleId}\" }\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph3/spaces/TooManySpacesEnumExpected.kt",
    "content": "package test.paragraph3.spaces\n\nenum class Warnings(private val id: Int, private val canBeAutoCorrected: Boolean, private val warn: String) : Rule {\n    PACKAGE_NAME_MISSING         (1, true,  \"no package name declared in a file\"),\n    PACKAGE_NAME_INCORRECT_CASE  (2, true,  \"package name should be completely in a lower case\"),\n    PACKAGE_NAME_INCORRECT_PREFIX(3, false, \"package name should start from company's domain\")\n    ;\n\n    fun some() {\n        val b = 5\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph3/spaces/TooManySpacesEnumTest.kt",
    "content": "package test.paragraph3.spaces\n\nenum             class               Warnings(private val id: Int, private val canBeAutoCorrected: Boolean, private val warn: String) : Rule {\n    PACKAGE_NAME_MISSING         (1, true,  \"no package name declared in a file\"),\n    PACKAGE_NAME_INCORRECT_CASE  (2, true,  \"package name should be completely in a lower case\"),\n    PACKAGE_NAME_INCORRECT_PREFIX(3, false, \"package name should start from company's domain\")\n    ;\n\n    fun some() {\n        val b =            5\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph3/spaces/TooManySpacesExpected.kt",
    "content": "package test.paragraph3.spaces\n\ndata class User(val name: String, val id: Int)\n\nfun main() {\n    val user = User(\"Alex\", 1)\n    println(user)\n\n    val secondUser = User(\"Alex\", 1)\n    val thirdUser = User(\"Max\", 2)\n\n    println(\"user == secondUser: ${user == secondUser}\")\n    println(\"user == thirdUser: ${user == thirdUser}\")\n\n    println(user.hashCode())\n    println(thirdUser.hashCode())\n\n    println(user.copy())\n    println(user.copy(\"Max\"))\n    println(user.copy(id = 2))\n\n    println(\"name = ${user.component1()}\")\n    println(\"id = ${user.component2()}\")\n}\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph3/spaces/TooManySpacesTest.kt",
    "content": "package test.paragraph3.spaces\n\ndata class User(val name: String, val id: Int)\n\nfun main() {\n    val user =                    User(\"Alex\", 1)\n    println(user)\n\n    val                   secondUser = User(\"Alex\", 1)\n    val thirdUser = User(\"Max\", 2)\n\n    println(\"user == secondUser: ${user == secondUser}\")\n    println(\"user == thirdUser: ${user == thirdUser}\")\n\n    println(user.hashCode())\n    println(thirdUser.hashCode())\n\n    println(user.copy())\n    println(user.copy(\"Max\"))\n    println(user.copy(id                      = 2))\n\n    println(\"name = ${user.component1()}\")\n    println(\"id = ${user.component2()}\")\n}\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph3/spaces/WhiteSpaceBeforeLBraceExpected.kt",
    "content": "package test.paragraph3.spaces\n\nclass Example {\n    fun foo() {\n        if (condition) { }\n        else {}\n        try { }\n        finally { }\n    }\n\n    fun bar() {\n        if (condition) { }\n        else {}\n        try { }\n        finally { }\n    }\n}"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph3/spaces/WhiteSpaceBeforeLBraceTest.kt",
    "content": "package test.paragraph3.spaces\n\nclass Example {\n    fun foo() {\n        if (condition) { }\n        else{}\n        try{ }\n        finally{ }\n    }\n\n    fun bar() {\n        if (condition) { }\n        else  {}\n        try   { }\n        finally   { }\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph3/spaces/WhiteSpaceBeforeLParExpected.kt",
    "content": "package test.paragraph3.spaces\n\nclass Example : SuperExample {\n    constructor(val a: Int)\n\n    fun foo() {\n        if (condition) { }\n        for (i in 1..100) { }\n        when (expression) { }\n    }\n\n    fun bar() {\n        if (condition) { }\n        for (i in 1..100) { }\n        when (expression) { }\n    }\n}\n\ndata class Example(\n    val foo: Foo,\n    val bar: Bar\n)\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph3/spaces/WhiteSpaceBeforeLParTest.kt",
    "content": "package test.paragraph3.spaces\n\nclass Example : SuperExample {\n    constructor (val a: Int)\n\n    fun foo() {\n        if(condition) { }\n        for(i in 1..100) { }\n        when(expression) { }\n    }\n\n    fun bar () {\n        if  (condition) { }\n        for  (i in 1..100) { }\n        when  (expression) { }\n    }\n}\n\ndata class Example (\n    val foo: Foo,\n    val bar: Bar\n)\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph3/src/main/A/FileSize2000.kt",
    "content": ""
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph3/src/main/A/FileSizeA.kt",
    "content": "package test.paragraph3.src.main.A\n\nclass A {\n\n    fun tester(a: Int) = Unit\n\n\n    fun testER(a: Int) = Unit\n}\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph3/src/main/B/FileSizeB.kt",
    "content": "package test.paragraph3.src.main.B\n\nclass B {\n\n    fun tester(a: Int) = Unit\n\n\n    fun testER(a: Int) = Unit\n}\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph3/src/main/C/FileSizeC.kt",
    "content": "package test.paragraph3.src.main.B\n\nclass B {\n\n    fun tester(a: Int) = Unit\n\n\n    fun testER(a: Int) = Unit\n}\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph3/src/main/FileSizeLarger.kt",
    "content": "\n//sdfsdf\n\nclass fg{\n    private val sdv = 1000\n}\n\n\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph3/statement/StatementExpected.kt",
    "content": "package test.paragraph3.statement\n\nimport com.pinterest.ktlint.core.KtLint\n import com.pinterest.ktlint.core.LintError\n\nfun foo(){\n    if (x > 0){\n        goo()\n qwe()\n    }\n}\n\nfun foo(){\n    if (x > 0){\n        goo()\nqwe()\n    }\n}\n\nfun foo() {\n     grr()\n}\n\nenum class ProtocolState {\n    WAITING {\n        override fun signal() = TALKING\n    },\n    TALKING {\n        override fun signal() = WAITING\n    };\n abstract fun signal(): ProtocolState\n}"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph3/statement/StatementTest.kt",
    "content": "package test.paragraph3.statement\n\nimport com.pinterest.ktlint.core.KtLint; import com.pinterest.ktlint.core.LintError\n\nfun foo(){\n    if (x > 0){\n        goo(); qwe()\n    }\n}\n\nfun foo(){\n    if (x > 0){\n        goo();qwe()\n    }\n}\n\nfun foo() {\n    ; grr()\n}\n\nenum class ProtocolState {\n    WAITING {\n        override fun signal() = TALKING\n    },\n    TALKING {\n        override fun signal() = WAITING\n    }; abstract fun signal(): ProtocolState\n}"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph3/string_concatenation/StringConcatenationExpected.kt",
    "content": "package test.chapter3.strings\n\nval valueStr = \"my str\"\nval x = 13\n\nfun foo(): String {\n    return \"string\"\n}\n\nval myTest1 = \"my string string $valueStr other value\"\nval myTest2 = \"my string 1$valueStr other value\"\nval myTest3 = \"my string $valueStr string other value\"\nval myTest4 = \"my string one two\"\nval myTest5 = \"trying to sum with multiline\"\nval myTest6 = \"trying to sum with \" + \"\"\"\n    multiline\"\"\".trimIndent()\nval myTest7 = \"multiline string\"\nval myTest8 = \"string ${valueStr.replace(\"my\", \"\")}\"\nval myTest9 = \"string ${\"valueStr\".replace(\"my\", \"\")}\"\nval myTest10 = \"string ${(1 + 5)}\"\nval myTest11 = \"sum other string 3 str2 5 other string 2 2 str3 4\"\nval myTest12 = \"my string 123\"\nval myTest13 = \"${(1 + 2)} my string 3 string $valueStr$valueStr\"\nval myTest14 = \"my string ${(1 + 2 + 3)} other string 3${(1 + 2 + 3)}\"\nval myTest15 = 1 + 2 + (\"13\").toInt()\nval myTest16 = 1.0 + 2.0 + (\"13.0\").toFloat()\nval myTest17 = \"sum ${(1 + 2 + 3) * 4}\"\nval myTest18 = \"my string ${(1 + 2 + 3) * 4} other string 3${(1 + (2 + 3))} third string str 5\"\nval myTest19 = 1 + 2 + 3 + (\"65\").toInt()\nval myTest20 = \"${x}string\"\nval myTest21 = \"${x} string\"\nval myTest22 = \"string${foo()}\"\nval myTest23 = x.toString() + foo()\nval myTest24 = foo() + \"string\"\nval myTest25 = \"String ${valueStr?.value}\"\nval myTest26 = \"my string ${if (true) \"1\" else \"2\"}\"\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph3/string_concatenation/StringConcatenationTest.kt",
    "content": "package test.chapter3.strings\n\nval valueStr = \"my str\"\nval x = 13\n\nfun foo(): String {\n    return \"string\"\n}\n\nval myTest1 = \"my string \" + \"string \" + valueStr + \" other value\"\nval myTest2 = \"my string \" + 1 + valueStr + \" other value\"\nval myTest3 = \"my string \" + valueStr + \" string \" + \"other value\"\nval myTest4 = \"my string\" + (\" one \" + \"two\")\nval myTest5 = \"trying to sum with \" + \"\"\"multiline\"\"\"\nval myTest6 = \"trying to sum with \" + \"\"\"\n    multiline\"\"\".trimIndent()\nval myTest7 = \"\"\"multiline\"\"\" + \" string\"\nval myTest8 = \"string \" + valueStr.replace(\"my\", \"\")\nval myTest9 = \"string \" + \"valueStr\".replace(\"my\", \"\")\nval myTest10 = \"string \" + (1 + 5)\nval myTest11 = \"sum \" + (\"other string \" + 3 + \" str2 \" + 5 + (\" other string 2 \" + 2 + \" str3 \" + 4))\nval myTest12 = \"my string \" + 1 + 2 + 3\nval myTest13 = (1 + 2).toString() + \" my string \" + 3 + \" string \" + valueStr + valueStr\nval myTest14 = \"my string \" + (1 + 2 + 3) + (\" other string \" + 3) + (1 + 2 + 3)\nval myTest15 = 1 + 2 + (\"1\" + 3).toInt()\nval myTest16 = 1.0 + 2.0 + (\"1\" + 3.0).toFloat()\nval myTest17 = \"sum \" + (1 + 2 + 3) * 4\nval myTest18 = \"my string \" + (1 + 2 + 3) * 4 + (\" other string \" + 3) + (1 + (2 + 3)) + (\" third string \" + (\"str \" + 5))\nval myTest19 = 1 + 2 + 3 + (\"6\" + 5).toInt()\nval myTest20 = x.toString() + \"string\"\nval myTest21 = x.toString() + \" string\"\nval myTest22 = \"string\" + foo()\nval myTest23 = x.toString() + foo()\nval myTest24 = foo() + \"string\"\nval myTest25 = \"String \" + valueStr?.value\nval myTest26 = \"my string \" + if (true) \"1\" else \"2\"\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph3/string_template/StringTemplateExpected.kt",
    "content": "package test.paragraph3.string_template\n\nclass SomeClass {\n    fun someFunc() {\n        val x = \"asd\"\n\n        val z = x\n\n        val m = \"1.0\"\n\n        val template = \"$x, ${asd.moo()}\"\n\n        val binExpr = \"${foo as Foo}\"\n\n        val trippleQuotes = x\n\n        val test = \"\"\"${'$'}\"\"\"\n\n        val test2= \"${'$'}1\"\n\n        val digitsWithLetters = \"1.0asd\"\n    }\n}"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph3/string_template/StringTemplateTest.kt",
    "content": "package test.paragraph3.string_template\n\nclass SomeClass {\n    fun someFunc() {\n        val x = \"asd\"\n\n        val z = \"$x\"\n\n        val m = \"${1.0}\"\n\n        val template = \"${x}, ${asd.moo()}\"\n\n        val binExpr = \"${foo as Foo}\"\n\n        val trippleQuotes = \"\"\"${x}\"\"\"\n\n        val test = \"\"\"${'$'}\"\"\"\n\n        val test2= \"${'$'}1\"\n\n        val digitsWithLetters = \"${1.0}asd\"\n    }\n}"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph3/top_level/TopLevelSortExpected.kt",
    "content": "package test.paragraph3.top_level\n\nconst val q = \"1\"\n\nval heh = 10\n\nprivate var t = 1\n\ntypealias StringConsumer = (String) -> Unit\n\ninternal typealias ExamplesList = List<IExample>\n\nprivate typealias UsersMap = Map<User, UserData>\n\nclass Qwe() {}\n\nfun String.qq() {}\n\ninternal fun kl() {}\n\nprivate fun foo() {}\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph3/top_level/TopLevelSortTest.kt",
    "content": "package test.paragraph3.top_level\n\nconst val q = \"1\"\n\nprivate fun foo() {}\n\nprivate typealias UsersMap = Map<User, UserData>\n\nclass Qwe() {}\n\nfun String.qq() {}\n\nprivate var t = 1\n\ninternal fun kl() {}\n\ninternal typealias ExamplesList = List<IExample>\n\nval heh = 10\n\ntypealias StringConsumer = (String) -> Unit\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph3/top_level/TopLevelWithCommentExpected.kt",
    "content": "/**\n * Some text here\n */\n\npackage test.paragraph3.top_level\n\nimport com.saveourtool.diktat.bar\n\nclass A {}\n\n/**\n * Hehe\n */\nfun String.ww() {}\n\n/**\n * Text for function\n */\nfun foo() {}\n\n\n/*\ntext here\n */\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph3/top_level/TopLevelWithCommentTest.kt",
    "content": "/**\n * Some text here\n */\n\npackage test.paragraph3.top_level\n\nimport com.saveourtool.diktat.bar\n\nclass A {}\n\n/**\n * Text for function\n */\nfun foo() {}\n\n/**\n * Hehe\n */\nfun String.ww() {}\n\n\n/*\ntext here\n */\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph3/trailing_comma/TrailingCommaExpected.kt",
    "content": "package test.paragraph3.trailing_comma\n\nclass Customer(\n    val name: String,\n    lastName: String,\n)\n\nfun shift(x: Int,\n          y: Int,\n) {\n    shift(\n        25,\n        20,\n    )\n\n    val colors = listOf(\n        \"red\",\n        \"green\",\n        \"blue\",\n    )\n}\n\nfun getZValue(mySurface: Surface,\n              xValue: Int,\n              yValue: Int,\n) =\n    mySurface[\n            xValue,\n            yValue\n    ]\n\nfun isReferenceApplicable(myReference: KClass<*>,\n) = when (myReference) {\n    Comparable::class,\n    Iterable::class,\n    String::class,\n    -> true\n    else -> false\n}\n\nfun isReferenceApplicable(myReference: KClass<*> ,// comment\n) = when (myReference) {\n    Comparable::class,\n    Iterable::class,\n    String::class,\n    -> true\n    else -> false\n}\n\n@ApplicableFor([\n    \"serializer\",\n    \"balancer\",\n    \"database\",\n    \"inMemoryCache\",\n],\n)\nfun foo() {}\n\nfun <T1,\n        T21,\n        > foo() {}\n\nfun mains() {\n    foo<\n            Comparable<Number,\n                    >,\n            Iterable<Number,\n                    >,\n            >()\n}\n\nfun printMeanValue() {\n    var meanValue: Int = 0\n    for ((\n        _,\n        _,\n        year,\n    ) in cars) {\n        meanValue += year\n    }\n    println(meanValue/cars.size)\n}\n\nenum class SomeEnum(\n    val a: Int, val b: Int  ,// comment\n)\n\nenum class SomeEnum(\n    val a: Int, val b: Int,// comment\n)\n\nenum class SomeEnum(\n    val a: Int, val b: Int  ,/* comment */\n)\n\nenum class SomeEnum(\n    val a: Int, val b: Int,  /**\n    some comment */\n)\n\nfun foo() {\n    val sum: (Int, Int, Int,) -> Int = fun(\n        x,\n        y,\n        z ,// trailing comma\n    ): Int {\n        return x + y + x\n    }\n    println(sum(8, 8, 8))\n}\n\nfun shift(x: Int, y: Int) {\n    shift(\n        25,\n        20, // trailing comma\n    )\n\n    val colors = listOf(\n        \"red\",\n        \"green\",\n        \"blue\", // trailing comma\n    )\n}"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph3/trailing_comma/TrailingCommaTest.kt",
    "content": "package test.paragraph3.trailing_comma\n\nclass Customer(\n    val name: String,\n    lastName: String\n)\n\nfun shift(x: Int,\n          y: Int\n) {\n    shift(\n        25,\n        20\n    )\n\n    val colors = listOf(\n        \"red\",\n        \"green\",\n        \"blue\"\n    )\n}\n\nfun getZValue(mySurface: Surface,\n              xValue: Int,\n              yValue: Int\n) =\n    mySurface[\n            xValue,\n            yValue\n    ]\n\nfun isReferenceApplicable(myReference: KClass<*>\n) = when (myReference) {\n    Comparable::class,\n    Iterable::class,\n    String::class\n    -> true\n    else -> false\n}\n\nfun isReferenceApplicable(myReference: KClass<*> // comment\n) = when (myReference) {\n    Comparable::class,\n    Iterable::class,\n    String::class\n    -> true\n    else -> false\n}\n\n@ApplicableFor([\n    \"serializer\",\n    \"balancer\",\n    \"database\",\n    \"inMemoryCache\"\n]\n)\nfun foo() {}\n\nfun <T1,\n        T21\n        > foo() {}\n\nfun mains() {\n    foo<\n            Comparable<Number\n                    >,\n            Iterable<Number\n                    >\n            >()\n}\n\nfun printMeanValue() {\n    var meanValue: Int = 0\n    for ((\n        _,\n        _,\n        year\n    ) in cars) {\n        meanValue += year\n    }\n    println(meanValue/cars.size)\n}\n\nenum class SomeEnum(\n    val a: Int, val b: Int  // comment\n)\n\nenum class SomeEnum(\n    val a: Int, val b: Int// comment\n)\n\nenum class SomeEnum(\n    val a: Int, val b: Int  /* comment */\n)\n\nenum class SomeEnum(\n    val a: Int, val b: Int  /**\n    some comment */\n)\n\nfun foo() {\n    val sum: (Int, Int, Int,) -> Int = fun(\n        x,\n        y,\n        z // trailing comma\n    ): Int {\n        return x + y + x\n    }\n    println(sum(8, 8, 8))\n}\n\nfun shift(x: Int, y: Int) {\n    shift(\n        25,\n        20 // trailing comma\n    )\n\n    val colors = listOf(\n        \"red\",\n        \"green\",\n        \"blue\" // trailing comma\n    )\n}"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph4/generics/VariableGenericTypeDeclarationExpected.kt",
    "content": "package test.paragraph4.generics\n\nclass SomeClass(val some: Map<Int, String> = emptyMap()) {\n    val myVariable: Map<Int, String> = emptyMap()\n\n    fun someFunc(myVariable: Map<Int, String> = emptyMap()) {}\n}\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph4/generics/VariableGenericTypeDeclarationTest.kt",
    "content": "package test.paragraph4.generics\n\nclass SomeClass(val some: Map<Int, String> = emptyMap<Int, String>()) {\n    val myVariable: Map<Int, String> = emptyMap<Int, String>()\n\n    fun someFunc(myVariable: Map<Int, String> = emptyMap<Int, String>()) {}\n}\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph4/null_checks/IfConditionAssignCheckExpected.kt",
    "content": "package test.paragraph4.null_checks\n\nfun foo() {\n    val x = a?.let {\nf(a)\n} ?: g(a)\n\n    val y = a ?: 0\n\n    x ?: println(\"NULL\")\n\n    val z = x ?: run {\nprintln(\"NULL\")\n0\n}\n\n    x?.let {\nf(x)\n} ?: run {\nprintln(\"NULL\")\ng(x)\n}\n}\n\nfun bar() {\n    val x = a?.let {\nf(a)\n} ?: g(a)\n\n    val y = a ?: 0\n\n    x ?: println(\"NULL\")\n\n    val z = x ?: run {\nprintln(\"NULL\")\n0\n}\n\n    x?.let {\nf(x)\n} ?: run {\nprintln(\"NULL\")\ng(x)\n}\n}\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph4/null_checks/IfConditionAssignCheckTest.kt",
    "content": "package test.paragraph4.null_checks\n\nfun foo() {\n    val x = if (a != null) f(a) else g(a)\n\n    val y = if (a != null) a else 0\n\n    if (x != null) {\n        x\n    } else {\n        println(\"NULL\")\n    }\n\n    val z = if (x != null) {\n        x\n    } else {\n        println(\"NULL\")\n        0\n    }\n\n    if (x != null) {\n        f(x)\n    } else {\n        println(\"NULL\")\n        g(x)\n    }\n}\n\nfun bar() {\n    val x = if (a == null) g(a) else f(a)\n\n    val y = if (a == null) 0 else a\n\n    if (x == null) {\n        println(\"NULL\")\n    } else {\n        x\n    }\n\n    val z = if (x == null) {\n        println(\"NULL\")\n        0\n    } else {\n        x\n    }\n\n    if (x == null) {\n        println(\"NULL\")\n        g(x)\n    } else {\n        f(x)\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph4/null_checks/IfConditionBreakCheckExpected.kt",
    "content": "package test.paragraph4.null_checks\n\n\nfun foo() {\n    var result: Int? = 19\n    while(result != 0 ) {\n        if (result == null) {\n            foo()\n        } else {\n            break\n        }\n    }\n}\n\nfun foo() {\n    var result: Int? = 19\n    while(result != 0 ) {\n        result?.let {\nfoo()\n} ?: break\n    }\n}\n\nfun foo() {\n    var result: Int? = 19\n    while(result != 0 ) {\n        if (result != null) {\n            break\n        } else {\n            foo()\n        }\n    }\n}\n\nfun foo() {\n    var result: Int? = 19\n    while(result != 0 ) {\n        result?.let {\nfoo()\n} ?: break\n    }\n}\n\nfun foo() {\n    var result: Int? = 19\n    while(result != 0 ) {\n        result ?: break\n    }\n}\n\nfun foo() {\n    var result: Int? = 19\n    while(result != 0 ) {\n        if (result != null) {\n            break\n        }\n    }\n}\n\nfun foo() {\n    var result: Int? = 19\n    while(result != 0 ) {\n        if (result != null) {\n            foo()\n            break\n        } else {\n            break\n        }\n    }\n}\n\nfun foo() {\n    var result: Int? = 19\n    while(result != 0 ) {\n        if (result != null) {\n            result?.let {\ngoo()\n} ?: break\n        } else {\n            break\n        }\n    }\n}\n\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph4/null_checks/IfConditionBreakCheckTest.kt",
    "content": "package test.paragraph4.null_checks\n\n\nfun foo() {\n    var result: Int? = 19\n    while(result != 0 ) {\n        if (result == null) {\n            foo()\n        } else {\n            break\n        }\n    }\n}\n\nfun foo() {\n    var result: Int? = 19\n    while(result != 0 ) {\n        if (result == null) {\n            break\n        } else {\n            foo()\n        }\n    }\n}\n\nfun foo() {\n    var result: Int? = 19\n    while(result != 0 ) {\n        if (result != null) {\n            break\n        } else {\n            foo()\n        }\n    }\n}\n\nfun foo() {\n    var result: Int? = 19\n    while(result != 0 ) {\n        if (result != null) {\n            foo()\n        } else {\n            break\n        }\n    }\n}\n\nfun foo() {\n    var result: Int? = 19\n    while(result != 0 ) {\n        if (result == null) {\n            break\n        }\n    }\n}\n\nfun foo() {\n    var result: Int? = 19\n    while(result != 0 ) {\n        if (result != null) {\n            break\n        }\n    }\n}\n\nfun foo() {\n    var result: Int? = 19\n    while(result != 0 ) {\n        if (result != null) {\n            foo()\n            break\n        } else {\n            break\n        }\n    }\n}\n\nfun foo() {\n    var result: Int? = 19\n    while(result != 0 ) {\n        if (result != null) {\n            if (result != null) {\n                goo()\n            } else {\n                break\n            }\n        } else {\n            break\n        }\n    }\n}\n\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph4/null_checks/IfConditionNullCheckExpected.kt",
    "content": "package test.paragraph4.null_checks\n\nfun test() {\n    val some: Int? = null\n    some ?: run {\nprintln(\"some\")\nbar()\n}\n\n    some?.let {\nprintln(\"some\")\nbar()\n}\n\n    if (some == null && true) {\n        print(\"asd\")\n    }\n\n    some?.let {\nprint(\"qwe\")\n} ?: print(\"asd\")\n\n    some?.let {\nprint(\"qweqwe\")\n}\n\n    some?.let {\nprint(\"qqq\")\n} ?: print(\"www\")\n\n    some?.let {\nprint(\"ttt\")\n}\n\n    some?.let {\nprint(\"ttt\")\n} ?: run {\nnull\nvalue\n}\n}\n\nfun foo() {\n    var result: Int? = 10\n    while (result != 0 ) {\n        result?.let {\ngoo()\n} ?: for(i in 1..10)\nbreak\n    }\n    while (result != 0) {\n        result = goo()\n        if (result != null) {\n            goo()\n        } else {\n            println(123)\n            break\n        }\n    }\n}\n\nfun checkSmartCases() {\n    val x = a?.toString() ?: \"Null\"\n    val y = a.b.c?.toString() ?: a.b.toString()\n    a?.let {\nprint()\n}\n    a?.let {\nfoo()\n} ?: boo()\n}\n\nfun reversedCheckSmartCases() {\n    val x = a?.toString() ?: \"Null\"\n    val y = a.b.c?.toString() ?: a.b.toString()\n    a ?: print()\n    a?.let {\nfoo()\n} ?: boo()\n}\n\nfun nullCheckWithAssumption() {\n    val a: Int? = 5\n    a?.let {\nfoo()\n} ?: run {\na = 5\n}\n    a?.let {\nfoo()\n} ?: run {\na = 5\n}\n    a?.let {\na = 5\n} ?: foo()\n    a?.let {\na = 5\n} ?: foo()\n    a?.let {\nfoo()\n} ?: a == 5\n}\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph4/null_checks/IfConditionNullCheckTest.kt",
    "content": "package test.paragraph4.null_checks\n\nfun test() {\n    val some: Int? = null\n    if (some == null) {\n        println(\"some\")\n        bar()\n    }\n\n    if (some != null) {\n        println(\"some\")\n        bar()\n    }\n\n    if (some == null && true) {\n        print(\"asd\")\n    }\n\n    if (some == null) {\n        print(\"asd\")\n    } else {\n        print(\"qwe\")\n    }\n\n    if (some == null) {\n        null\n    } else {\n        print(\"qweqwe\")\n    }\n\n    if (some != null) {\n        print(\"qqq\")\n    } else {\n        print(\"www\")\n    }\n\n    if (some != null) {\n        print(\"ttt\")\n    } else {\n        null\n    }\n\n    if (some != null) {\n        print(\"ttt\")\n    } else {\n        null\n        value\n    }\n}\n\nfun foo() {\n    var result: Int? = 10\n    while (result != 0 ) {\n        if (result != null) {\n            goo()\n        } else {\n            for(i in 1..10)\n                break\n        }\n    }\n    while (result != 0) {\n        result = goo()\n        if (result != null) {\n            goo()\n        } else {\n            println(123)\n            break\n        }\n    }\n}\n\nfun checkSmartCases() {\n    val x = if (a != null) {\n        a.toString()\n    } else {\n        \"Null\"\n    }\n    val y = if (a.b.c != null) {\n        a.b.c.toString()\n    } else {\n        a.b.toString()\n    }\n    if (a != null) {\n        print()\n    }\n    if (a != null) {\n        foo()\n    } else {\n        boo()\n    }\n}\n\nfun reversedCheckSmartCases() {\n    val x = if (a == null) {\n        \"Null\"\n    } else {\n        a.toString()\n    }\n    val y = if (a.b.c == null) {\n        a.b.toString()\n    } else {\n        a.b.c.toString()\n    }\n    if (a == null) {\n        print()\n    }\n    if (a == null) {\n        boo()\n    } else {\n        foo()\n    }\n}\n\nfun nullCheckWithAssumption() {\n    val a: Int? = 5\n    if (a != null) {\n        foo()\n    } else {\n        a = 5\n    }\n    if (a == null) {\n        a = 5\n    } else {\n        foo()\n    }\n    if (a != null) {\n        a = 5\n    } else {\n        foo()\n    }\n    if (a == null) {\n        foo()\n    } else {\n        a = 5\n    }\n    if (a != null) {\n        foo()\n    } else {\n        a == 5\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph4/null_checks/RequireFunctionExpected.kt",
    "content": "package test.paragraph4.null_checks\n\nfun test() {\n    val some: Int? = null\n\n    requireNotNull(some)\n}\n\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph4/null_checks/RequireFunctionTest.kt",
    "content": "package test.paragraph4.null_checks\n\nfun test() {\n    val some: Int? = null\n\n    require(some != null)\n}\n\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph4/smart_cast/SmartCastExpected.kt",
    "content": "package test.paragraph4.smart_cast\n\nclass Some {\n    val x = \"\"\n\n    fun someFunc() {\n        if (x is String) {\n            print(x.length)\n            var a = x\n        }\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph4/smart_cast/SmartCastTest.kt",
    "content": "package test.paragraph4.smart_cast\n\nclass Some {\n    val x = \"\"\n\n    fun someFunc() {\n        if (x is String) {\n            print((x as String).length)\n            var a = x as String\n        }\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph5/method_call_names/ReplaceMethodCallNamesExpected.kt",
    "content": "package test.chapter6.method_call_names\n\nfun coolFunction() {\n    val list = listOf(1, 2, 3)\n    val testStr = \"\"\n\n    if (list.isEmpty()) { }\n\n    if (list.isNotEmpty()) { }\n\n    if (list.isNotEmpty()) { }\n\n    if (list.isEmpty()) { }\n\n    if (testStr.isBlank()) { }\n\n    if (testStr.isNotBlank()) { }\n\n    if (testStr.isNotBlank()) { }\n\n    if (testStr.isBlank()) { }\n\n    if (list.isNotEmpty() && testStr.isBlank()) { }\n}\n\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph5/method_call_names/ReplaceMethodCallNamesTest.kt",
    "content": "package test.chapter6.method_call_names\n\nfun coolFunction() {\n    val list = listOf(1, 2, 3)\n    val testStr = \"\"\n\n    if (list.isEmpty()) { }\n\n    if (list.isNotEmpty()) { }\n\n    if (!list.isEmpty()) { }\n\n    if (!list.isNotEmpty()) { }\n\n    if (testStr.isBlank()) { }\n\n    if (testStr.isNotBlank()) { }\n\n    if (!testStr.isBlank()) { }\n\n    if (!testStr.isNotBlank()) { }\n\n    if (!list.isEmpty() && !testStr.isNotBlank()) { }\n}\n\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph5/nested_functions/AvoidNestedFunctionsExample.kt",
    "content": "package test.paragraph5.nested_functions\n\nfun anotherFun() {\n        val b = 3\n    }\nfun someFunc() {\n    val a = 5\n}"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph5/nested_functions/AvoidNestedFunctionsNoTriggerExample.kt",
    "content": "package test.paragraph5.nested_functions\n\nfun some() {\n    var str = \"asd\"\n    fun another() {\n        str = \"sws\"\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph5/nested_functions/AvoidNestedFunctionsNoTriggerTest.kt",
    "content": "package test.paragraph5.nested_functions\n\nfun some() {\n    var str = \"asd\"\n    fun another() {\n        str = \"sws\"\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph5/nested_functions/AvoidNestedFunctionsSeveralExample.kt",
    "content": "package test.paragraph5.nested_functions\n\nfun some() {}\nfun baz() {\n        }\nfun bar() {\n    }\nfun foo() {\n}"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph5/nested_functions/AvoidNestedFunctionsSeveralTest.kt",
    "content": "package test.paragraph5.nested_functions\n\nfun foo() {\n    fun bar() {\n        fun baz() {\n            fun some() {}\n        }\n    }\n}"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph5/nested_functions/AvoidNestedFunctionsTest.kt",
    "content": "package test.paragraph5.nested_functions\n\nfun someFunc() {\n    val a = 5\n    fun anotherFun() {\n        val b = 3\n    }\n}"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph6/useless-override/SeveralSuperTypesExpected.kt",
    "content": "package test.paragraph6.`useless-override`\n\nopen class A {\n    open fun foo(){}\n}\n\ninterface C {\n    fun foo(){}\n    fun goo(){}\n}\n\nclass B: A(){\n    override fun foo() {\n        super.foo()\n    }\n}\n\nclass D: A(), C {\n    override fun foo() {\n        super<C>.foo()\n        super<A>.foo()\n        super.goo()\n    }\n\n    private fun qwe(){\n        val q = super.goo()\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph6/useless-override/SeveralSuperTypesTest.kt",
    "content": "package test.paragraph6.`useless-override`\n\nopen class A {\n    open fun foo(){}\n}\n\ninterface C {\n    fun foo(){}\n    fun goo(){}\n}\n\nclass B: A(){\n    override fun foo() {\n        super<A>.foo()\n    }\n}\n\nclass D: A(), C {\n    override fun foo() {\n        super<C>.foo()\n        super<A>.foo()\n        super<C>.goo()\n    }\n\n    private fun qwe(){\n        val q = super<C>.goo()\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph6/useless-override/UselessOverrideExpected.kt",
    "content": "package test.paragraph6\n\nopen class Rectangle {\n    open fun draw() { /* ... */ }\n}\n\nclass Square() : Rectangle() {\n    override fun draw() {\n        /**\n         *\n         * hehe\n         */\n        super.draw()\n    }\n}\n\nclass Square2() : Rectangle() {\n    override fun draw() {\n        //hehe\n        /*\n            hehe\n        */\n        super.draw()\n    }\n}\n\nclass Square2() : Rectangle() {\n    override fun draw() {\n        val q = super.draw()\n    }\n}\n\nclass A: Runnable {\n    override fun run() {\n\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test/paragraph6/useless-override/UselessOverrideTest.kt",
    "content": "package test.paragraph6\n\nopen class Rectangle {\n    open fun draw() { /* ... */ }\n}\n\nclass Square() : Rectangle() {\n    override fun draw() {\n        /**\n         *\n         * hehe\n         */\n        super<Rectangle>.draw()\n    }\n}\n\nclass Square2() : Rectangle() {\n    override fun draw() {\n        //hehe\n        /*\n            hehe\n        */\n        super<Rectangle>.draw()\n    }\n}\n\nclass Square2() : Rectangle() {\n    override fun draw() {\n        val q = super.draw()\n    }\n}\n\nclass A: Runnable {\n    override fun run() {\n\n    }\n}\n"
  },
  {
    "path": "diktat-rules/src/test/resources/test-rules-config.yml",
    "content": "- name: DIKTAT_COMMON\n  enabled: true\n  configuration:\n    domainName: com.saveourtool.diktat\n    kotlinVersion: 1.4.21\n    testDirs: \"test, androidUnitTest\"\n- name: CLASS_NAME_INCORRECT\n  enabled: true\n- name: CONSTANT_UPPERCASE\n  enabled: true\n- name: ENUM_VALUE\n  enabled: true\n- name: EXCEPTION_SUFFIX\n  enabled: true\n  configuration: { }\n- name: FILE_NAME_INCORRECT\n  enabled: true\n- name: FILE_NAME_MATCH_CLASS\n  enabled: true\n- name: FUNCTION_BOOLEAN_PREFIX\n  enabled: true\n- name: FUNCTION_NAME_INCORRECT_CASE\n  enabled: true\n- name: TYPEALIAS_NAME_INCORRECT_CASE\n  enabled: true\n- name: GENERIC_NAME\n  enabled: true\n- name: IDENTIFIER_LENGTH\n  enabled: true\n- name: OBJECT_NAME_INCORRECT\n  enabled: true\n- name: PACKAGE_NAME_INCORRECT_CASE\n  enabled: true\n- name: PACKAGE_NAME_INCORRECT_PREFIX\n  enabled: true\n- name: PACKAGE_NAME_INCORRECT_SYMBOLS\n  enabled: true\n- name: PACKAGE_NAME_INCORRECT_PATH\n  enabled: true\n- name: PACKAGE_NAME_MISSING\n  enabled: true\n- name: VARIABLE_HAS_PREFIX\n  enabled: true\n- name: VARIABLE_NAME_INCORRECT\n  enabled: true\n- name: VARIABLE_NAME_INCORRECT_FORMAT\n  enabled: true\n- name: MISSING_KDOC_ON_FUNCTION\n  enabled: true\n- name: MISSING_KDOC_TOP_LEVEL\n  enabled: true\n- name: MISSING_KDOC_CLASS_ELEMENTS\n  enabled: true\n- name: KDOC_WITHOUT_PARAM_TAG\n  enabled: true\n- name: KDOC_WITHOUT_RETURN_TAG\n  enabled: true\n- name: KDOC_WITHOUT_THROWS_TAG\n  enabled: true\n- name: KDOC_EMPTY_KDOC\n  enabled: true\n- name: INCORRECT_PACKAGE_SEPARATOR\n  enabled: true\n- name: KDOC_NO_DEPRECATED_TAG\n  enabled: true\n- name: KDOC_NO_EMPTY_TAGS\n  enabled: true\n- name: KDOC_WRONG_SPACES_AFTER_TAG\n  enabled: true\n- name: KDOC_WRONG_TAGS_ORDER\n  enabled: true\n- name: KDOC_NO_NEWLINES_BETWEEN_BASIC_TAGS\n  enabled: true\n- name: KDOC_NEWLINES_BEFORE_BASIC_TAGS\n  enabled: true\n- name: KDOC_NO_NEWLINE_AFTER_SPECIAL_TAGS\n  enabled: true\n- name: KDOC_TRIVIAL_KDOC_ON_FUNCTION\n  enabled: 'true'\n- name: HEADER_WRONG_FORMAT\n  enabled: true\n- name: HEADER_MISSING_IN_NON_SINGLE_CLASS_FILE\n  enabled: true\n- name: HEADER_MISSING_OR_WRONG_COPYRIGHT\n  enabled: true\n  configuration:\n    isCopyrightMandatory: false\n    copyrightText: Copyright (c) This is an example. 2012-2020. All rights reserved.\n- name: HEADER_NOT_BEFORE_PACKAGE\n  enabled: true\n- name: KDOC_CONTAINS_DATE_OR_AUTHOR\n  enabled: true\n- name: FILE_IS_TOO_LONG\n  enabled: true\n  configuration:\n    maxSize: '2000'\n- name: COMMENTED_OUT_CODE\n  enabled: true\n- name: FILE_CONTAINS_ONLY_COMMENTS\n  enabled: true\n- name: FILE_UNORDERED_IMPORTS\n  enabled: true\n- name: FILE_INCORRECT_BLOCKS_ORDER\n  enabled: true\n- name: FILE_NO_BLANK_LINE_BETWEEN_BLOCKS\n  enabled: true\n- name: FILE_WILDCARD_IMPORTS\n  enabled: true\n  configuration:\n    allowedWildcards: \"\" # Allowed wildcards for imports (e.g. \"import com.saveourtool.diktat.*, import org.jetbrains.kotlin.*\")\n    useRecommendedImportsOrder: true\n- name: NO_BRACES_IN_CONDITIONALS_AND_LOOPS\n  enabled: true\n- name: WRONG_ORDER_IN_CLASS_LIKE_STRUCTURES\n  enabled: true\n- name: BLANK_LINE_BETWEEN_PROPERTIES\n  enabled: true\n- name: BRACES_BLOCK_STRUCTURE_ERROR\n  enabled: true\n  configuration:\n    openBraceNewline: 'True'\n    closeBraceNewline: 'True'\n- name: WRONG_INDENTATION\n  enabled: true\n  configuration:\n    newlineAtEnd: true\n    extendedIndentOfParameters: false\n    alignedParameters: true\n    extendedIndentForExpressionBodies: false\n    extendedIndentAfterOperators: true\n    indentationSize: 4\n- name: EMPTY_BLOCK_STRUCTURE_ERROR\n  enabled: true\n  configuration:\n    styleEmptyBlockWithNewline: 'True'\n    allowEmptyBlocks: 'False'\n- name: MORE_THAN_ONE_STATEMENT_PER_LINE\n  enabled: true\n- name: LONG_LINE\n  enabled: true\n  configuration:\n    lineLength: '120'\n- name: REDUNDANT_SEMICOLON\n  enabled: true\n- name: WRONG_NEWLINES\n  enabled: true\n- name: TOO_MANY_CONSECUTIVE_SPACES\n  enabled: true\n  configuration:\n    max_spaces: '1'\n    saveInitialFormattingForEnums: false\n- name: TOO_MANY_BLANK_LINES\n  enabled: true\n- name: WRONG_WHITESPACE\n  enabled: true\n- name: BACKTICKS_PROHIBITED\n  enabled: true\n- name: STRING_CONCATENATION\n  enabled: true\n- name: WHEN_WITHOUT_ELSE\n  enabled: true\n- name: ANNOTATION_NEW_LINE\n  enabled: true\n- name: ENUMS_SEPARATED\n  enabled: true\n- name: LONG_NUMERICAL_VALUES_SEPARATED\n  enabled: true\n  configuration:\n    maxNumberLength: '5'\n    maxBlockLength: '3'\n- name: WRONG_DECLARATIONS_ORDER\n  enabled: true\n  configuration:\n    sortEnum: true\n    sortProperty: true\n- name: WRONG_MULTIPLE_MODIFIERS_ORDER\n  enabled: true\n"
  },
  {
    "path": "diktat-ruleset/build.gradle.kts",
    "content": "import com.saveourtool.diktat.buildutils.configurePom\nimport com.saveourtool.diktat.buildutils.configurePublications\nimport com.github.jengelman.gradle.plugins.shadow.ShadowExtension\nimport com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar\n\n@Suppress(\"DSL_SCOPE_VIOLATION\", \"RUN_IN_SCRIPT\")  // https://github.com/gradle/gradle/issues/22797\nplugins {\n    id(\"com.saveourtool.diktat.buildutils.kotlin-jvm-configuration\")\n    id(\"com.saveourtool.diktat.buildutils.code-quality-convention\")\n    id(\"com.saveourtool.diktat.buildutils.publishing-configuration\")\n    alias(libs.plugins.shadow)\n    `maven-publish`\n}\n\nproject.description = \"This module builds jar that can be used to run diktat using ktlint -R via command line\"\n\ndependencies {\n    api(projects.diktatRules) {\n        // Kotlin runtime & libraries will be provided by ktlint executable\n        exclude(\"org.jetbrains.kotlin\", \"kotlin-stdlib-common\")\n        exclude(\"org.jetbrains.kotlin\", \"kotlin-stdlib-jdk8\")\n        exclude(\"org.jetbrains.kotlin\", \"kotlin-stdlib\")\n        exclude(\"org.jetbrains.kotlin\", \"kotlin-compiler-embeddable\")\n    }\n    implementation(projects.diktatKtlintEngine) {\n        // Kotlin runtime & libraries will be provided by ktlint executable\n        exclude(\"org.jetbrains.kotlin\", \"kotlin-stdlib-common\")\n        exclude(\"org.jetbrains.kotlin\", \"kotlin-stdlib-jdk8\")\n        exclude(\"org.jetbrains.kotlin\", \"kotlin-stdlib\")\n        exclude(\"org.jetbrains.kotlin\", \"kotlin-compiler-embeddable\")\n    }\n    implementation(libs.ktlint.cli.ruleset.core)\n    implementation(libs.ktlint.logger)\n    implementation(libs.slf4j.api)\n}\n\ntasks.named<ShadowJar>(\"shadowJar\") {\n    archiveBaseName.set(\"diktat\")\n    archiveClassifier.set(\"\")\n    // need to relocate serialization from kaml to avoid conflicts with KtLint\n    relocate(\"kotlinx.serialization\", \"com.saveourtool.kotlinx_serialization\")\n    duplicatesStrategy = DuplicatesStrategy.FAIL\n}\n\n// disable default jar\ntasks.named(\"jar\") {\n    enabled = false\n}\n\n// it triggers shadowJar with default build\ntasks {\n    build {\n        dependsOn(shadowJar)\n    }\n    test {\n        dependsOn(shadowJar)\n    }\n}\n\npublishing {\n    publications {\n        // it creates a publication for shadowJar\n        create<MavenPublication>(\"shadow\") {\n            // https://github.com/johnrengelman/shadow/issues/417#issuecomment-830668442\n            project.extensions.configure<ShadowExtension> {\n                component(this@create)\n            }\n            this.artifactId = \"diktat\"\n            this.pom {\n                configurePom(project)\n                // need to override name\n                name.set(\"diktat\")\n            }\n        }\n    }\n}\nconfigurePublications()\n"
  },
  {
    "path": "diktat-ruleset/src/main/kotlin/com/saveourtool/diktat/ruleset/rules/DiktatRuleSetProviderV3Spi.kt",
    "content": "package com.saveourtool.diktat.ruleset.rules\n\nimport com.saveourtool.diktat.DIKTAT_ANALYSIS_CONF\nimport com.saveourtool.diktat.common.config.rules.DIKTAT_CONF_PROPERTY\nimport com.saveourtool.diktat.common.config.rules.DIKTAT_RULE_SET_ID\nimport com.saveourtool.diktat.ktlint.KtLintRuleWrapper.Companion.toKtLint\nimport com.saveourtool.diktat.ruleset.config.DiktatRuleConfigYamlReader\nimport com.pinterest.ktlint.cli.ruleset.core.api.RuleSetProviderV3\nimport com.pinterest.ktlint.logger.api.initKtLintKLogger\nimport com.pinterest.ktlint.rule.engine.core.api.RuleProvider\nimport com.pinterest.ktlint.rule.engine.core.api.RuleSetId\nimport io.github.oshai.kotlinlogging.KotlinLogging\nimport org.slf4j.Logger\nimport java.io.File\nimport java.io.InputStream\n\n/**\n * [RuleSetProviderV3] that provides diKTat ruleset.\n *\n * By default, it is expected to have `diktat-analysis.yml` configuration in the root folder where 'ktlint' is run\n * otherwise it will use default configuration where some rules are disabled.\n *\n * This class is registered in [resources/META-INF/services/com.pinterest.ktlint.cli.ruleset.core.api.RuleSetProviderV3]\n *\n * The no-argument constructor is used by the Java SPI interface.\n */\nclass DiktatRuleSetProviderV3Spi : RuleSetProviderV3(\n    id = RuleSetId(DIKTAT_RULE_SET_ID),\n) {\n    private val diktatRuleConfigReader = DiktatRuleConfigYamlReader()\n    private val diktatRuleSetFactory = DiktatRuleSetFactoryImpl()\n\n    init {\n        // Need to init KtLint logger to set log level from CLI\n        KotlinLogging.logger(Logger.ROOT_LOGGER_NAME).initKtLintKLogger()\n    }\n\n    override fun getRuleProviders(): Set<RuleProvider> = diktatRuleSetFactory(diktatRuleConfigReader(readConfigFile()))\n        .toKtLint()\n\n    private fun readConfigFile(): InputStream {\n        val resourceFileName = resolveConfigFile()\n        val resourceFile = File(resourceFileName)\n        return if (resourceFile.exists()) {\n            log.debug { \"Using $DIKTAT_ANALYSIS_CONF file from the following path: ${resourceFile.absolutePath}\" }\n            resourceFile.inputStream()\n        } else {\n            log.debug { \"Using the default $DIKTAT_ANALYSIS_CONF file from the class path\" }\n            javaClass.classLoader.getResourceAsStream(resourceFileName) ?: run {\n                log.error { \"Not able to open file $resourceFileName from the resources\" }\n                object : InputStream() {\n                    override fun read(): Int = -1\n                }\n            }\n        }\n    }\n\n    private fun resolveConfigFile(): String {\n        val possibleConfigs: Sequence<String?> = sequence {\n            yield(DIKTAT_ANALYSIS_CONF)\n            yield(resolveConfigFileFromJarLocation())\n            yield(resolveConfigFileFromSystemProperty())\n        }\n\n        log.debug {\n            \"Will run $DIKTAT_RULE_SET_ID with $DIKTAT_ANALYSIS_CONF\" +\n                    \" (it can be placed to the run directory or the default file from resources will be used)\"\n        }\n        val configPath = possibleConfigs\n            .firstOrNull { it != null && File(it).exists() }\n        return configPath\n            ?: run {\n                val possibleConfigsList = possibleConfigs.toList()\n                log.warn {\n                    \"Configuration file not found in directory where diktat is run (${possibleConfigsList[0]}) \" +\n                            \"or in the directory where diktat.jar is stored (${possibleConfigsList[1]}) \" +\n                            \"or in system property <diktat.config.path> (${possibleConfigsList[2]}), \" +\n                            \"the default file included in jar will be used. \" +\n                            \"Some configuration options will be disabled or substituted with defaults. \" +\n                            \"Custom configuration file should be placed in diktat working directory if run from CLI \" +\n                            \"or provided as configuration options in plugins.\"\n                }\n                DIKTAT_ANALYSIS_CONF\n            }\n    }\n\n    private fun resolveConfigFileFromJarLocation(): String {\n        // for some aggregators of static analyzers we need to provide configuration for cli\n        // in this case diktat would take the configuration from the directory where jar file is stored\n        val ruleSetProviderPath = javaClass\n            .protectionDomain\n            .codeSource\n            .location\n            .toURI()\n\n        val configPathWithFileName = File(ruleSetProviderPath).absolutePath\n\n        val indexOfName = configPathWithFileName.lastIndexOf(File.separator)\n        val configPath = if (indexOfName > -1) configPathWithFileName.substring(0, indexOfName) else configPathWithFileName\n\n        return \"$configPath${File.separator}$DIKTAT_ANALYSIS_CONF\"\n    }\n\n    private fun resolveConfigFileFromSystemProperty(): String? = System.getProperty(DIKTAT_CONF_PROPERTY)\n\n    companion object {\n        private val log = KotlinLogging.logger {}\n    }\n}\n"
  },
  {
    "path": "diktat-ruleset/src/main/resources/META-INF/services/com.pinterest.ktlint.cli.ruleset.core.api.RuleSetProviderV3",
    "content": "com.saveourtool.diktat.ruleset.rules.DiktatRuleSetProviderV3Spi\n"
  },
  {
    "path": "diktat-runner/build.gradle.kts",
    "content": "import com.saveourtool.diktat.buildutils.configurePublications\nimport com.saveourtool.diktat.buildutils.configurePublishing\n\n@Suppress(\"DSL_SCOPE_VIOLATION\", \"RUN_IN_SCRIPT\")  // https://github.com/gradle/gradle/issues/22797\nplugins {\n    id(\"com.saveourtool.diktat.buildutils.kotlin-jvm-configuration\")\n    id(\"com.saveourtool.diktat.buildutils.code-quality-convention\")\n    id(\"com.saveourtool.diktat.buildutils.publishing-configuration\")\n    alias(libs.plugins.shadow)\n}\n\nproject.description = \"This module contains runner for diktat\"\n\ndependencies {\n    api(projects.diktatApi)\n    implementation(projects.diktatKtlintEngine)\n    implementation(projects.diktatRules)\n}\n\ntasks.shadowJar {\n    archiveClassifier.set(\"shadow\")\n    duplicatesStrategy = DuplicatesStrategy.FAIL\n}\n\n// https://github.com/gradle/gradle/issues/10384#issuecomment-1279708395\nval shadowElement: Configuration by configurations.creating {\n    isCanBeConsumed = true\n    isCanBeResolved = false\n    attributes {\n        attribute(Category.CATEGORY_ATTRIBUTE, objects.named(Category.LIBRARY))\n        attribute(Usage.USAGE_ATTRIBUTE, objects.named(Usage.JAVA_RUNTIME))\n        attribute(Bundling.BUNDLING_ATTRIBUTE, objects.named(Bundling.SHADOWED))\n    }\n    outgoing.artifact(tasks.shadowJar)\n}\ncomponents.named<AdhocComponentWithVariants>(\"java\").configure {\n    addVariantsFromConfiguration(shadowElement) {}\n}\n\npublishing {\n    publications {\n        create<MavenPublication>(\"maven\") {\n            from(components[\"java\"])\n        }\n    }\n}\nconfigurePublications()\nconfigurePublishing()\n"
  },
  {
    "path": "diktat-runner/src/main/kotlin/com/saveourtool/diktat/DiktatFactories.kt",
    "content": "/**\n * Contains only initialized factories\n */\n\npackage com.saveourtool.diktat\n\nimport com.saveourtool.diktat.api.DiktatBaselineFactory\nimport com.saveourtool.diktat.api.DiktatReporterFactory\nimport com.saveourtool.diktat.api.DiktatRuleConfigReader\nimport com.saveourtool.diktat.api.DiktatRuleSetFactory\nimport com.saveourtool.diktat.ktlint.DiktatBaselineFactoryImpl\nimport com.saveourtool.diktat.ktlint.DiktatProcessorFactoryImpl\nimport com.saveourtool.diktat.ktlint.DiktatReporterFactoryImpl\nimport com.saveourtool.diktat.ruleset.config.DiktatRuleConfigYamlReader\nimport com.saveourtool.diktat.ruleset.rules.DiktatRuleSetFactoryImpl\nimport generated.KTLINT_VERSION\n\n/**\n * Info about engine\n */\nconst val ENGINE_INFO: String = \"Ktlint: $KTLINT_VERSION\"\n\n/**\n * @return initialized [DiktatRuleConfigReader]\n */\nval diktatRuleConfigReader: DiktatRuleConfigReader = DiktatRuleConfigYamlReader()\n\n/**\n * @return initialized [DiktatRuleSetFactory]\n */\nval diktatRuleSetFactory: DiktatRuleSetFactory = DiktatRuleSetFactoryImpl()\n\n/**\n * @return initialized [DiktatProcessorFactory]\n */\nval diktatProcessorFactory: DiktatProcessorFactory = DiktatProcessorFactoryImpl()\n\n/**\n * @return initialized [DiktatBaselineFactory]\n */\nval diktatBaselineFactory: DiktatBaselineFactory = DiktatBaselineFactoryImpl()\n\n/**\n * @return initialized [DiktatReporterFactory]\n */\nval diktatReporterFactory: DiktatReporterFactory = DiktatReporterFactoryImpl()\n\n/**\n * @return initialized [DiktatRunnerFactory]\n */\nval diktatRunnerFactory: DiktatRunnerFactory = DiktatRunnerFactory(\n    diktatRuleConfigReader,\n    diktatRuleSetFactory,\n    diktatProcessorFactory,\n    diktatBaselineFactory,\n    diktatReporterFactory,\n)\n"
  },
  {
    "path": "examples/README.md",
    "content": ""
  },
  {
    "path": "examples/gradle-groovy-dsl/build.gradle",
    "content": "plugins {\n    id \"com.saveourtool.diktat\" version \"2.0.0\"\n}\n\nrepositories {\n    mavenCentral()\n}\n\ndiktat {\n    inputs { it.include (\"src/**/*.kt\") }\n    diktatConfigFile = file(rootDir.path + \"/diktat-analysis.yml\")\n}\n"
  },
  {
    "path": "examples/gradle-groovy-dsl/diktat-analysis.yml",
    "content": "# Common configuration\n- name: DIKTAT_COMMON\n  configuration:\n    # put your package name here - it will be autofixed and checked\n    domainName: your.name.here\n    testDirs: test\n    # expected values:  disabledChapters: \"Naming, Comments, General, Variables, Functions, Classes\"\n    # or: \"1, 2, 3, 4, 5, 6\"\n    disabledChapters: \"\"\n    kotlinVersion: 2.1\n    srcDirectories: \"main\"\n# Checks that the Class/Enum/Interface name matches Pascal case\n- name: CLASS_NAME_INCORRECT\n  enabled: true\n  # all code blocks with MyAnnotation will be ignored and not checked\n  ignoreAnnotated: [ MyAnnotation ]\n# Checks that CONSTANT (treated as const val from companion object or class level) is in non UPPER_SNAKE_CASE\n- name: CONSTANT_UPPERCASE\n  enabled: true\n# Checks that enum value is in upper SNAKE_CASE or in PascalCase depending on the config. UPPER_SNAKE_CASE is the default, but can be changed by 'enumStyle' config\n- name: ENUM_VALUE\n  enabled: true\n  configuration:\n    # Two options: SNAKE_CASE (default), PascalCase\n    enumStyle: SNAKE_CASE\n# Checks that class which extends any Exception class has Exception suffix\n- name: EXCEPTION_SUFFIX\n  enabled: true\n# Checks that file name has extension\n- name: FILE_NAME_INCORRECT\n  enabled: true\n# Checks that file name matches class name, if it is only one class in file\n- name: FILE_NAME_MATCH_CLASS\n  enabled: true\n# Checks that functions/methods which return boolean have special prefix like \"is/should/e.t.c\"\n- name: FUNCTION_BOOLEAN_PREFIX\n  enabled: true\n  configuration:\n    allowedPrefixes: \"\" # A list of functions that return boolean and are allowed to use. Input is in a form \"foo, bar\".\n# Checks that function/method name is in lowerCamelCase\n- name: FUNCTION_NAME_INCORRECT_CASE\n  enabled: true\n# Checks that typealias name is in PascalCase\n- name: TYPEALIAS_NAME_INCORRECT_CASE\n  enabled: true\n# Checks that generic name doesn't contain more than 1 letter (capital). It can be followed by numbers, example: T12, T\n- name: GENERIC_NAME\n  enabled: true\n# Identifier length should be in range [2,64] except names that used in industry like {i, j} and 'e' for catching exceptions\n- name: IDENTIFIER_LENGTH\n  enabled: true\n# Checks that the object matches PascalCase\n- name: OBJECT_NAME_INCORRECT\n  enabled: true\n# Checks that package name is in correct (lower) case\n- name: PACKAGE_NAME_INCORRECT_CASE\n  enabled: true\n# Checks that package name starts with the company's domain\n- name: PACKAGE_NAME_INCORRECT_PREFIX\n  enabled: false\n# Checks that package name does not have incorrect symbols like underscore or non-ASCII letters/digits\n- name: PACKAGE_NAME_INCORRECT_SYMBOLS\n  enabled: true\n# Checks that the path for a file matches with a package name\n- name: PACKAGE_NAME_INCORRECT_PATH\n  enabled: false\n# Checks that package name is in the file\n- name: PACKAGE_NAME_MISSING\n  enabled: true\n# Checks that variable does not have prefix (like mVariable or M_VARIABLE)\n- name: VARIABLE_HAS_PREFIX\n  enabled: true\n# Checks that variable does not contain one single letter, only exceptions are fixed names that used in industry like {i, j}\n- name: VARIABLE_NAME_INCORRECT\n  enabled: true\n# Checks that the name of variable is in lowerCamelCase and contains only ASCII letters\n- name: VARIABLE_NAME_INCORRECT_FORMAT\n  enabled: true\n# Checks that functions have kdoc\n- name: MISSING_KDOC_ON_FUNCTION\n  enabled: true\n# Checks that on file level internal or public class or function has missing KDoc\n- name: MISSING_KDOC_TOP_LEVEL\n  enabled: true\n# Checks that accessible internal elements (protected, public, internal) in a class are documented\n- name: MISSING_KDOC_CLASS_ELEMENTS\n  enabled: true\n# Checks that accessible method parameters are documented in KDoc\n- name: KDOC_WITHOUT_PARAM_TAG\n  enabled: true\n# Checks that accessible method explicit return type is documented in KDoc\n- name: KDOC_WITHOUT_RETURN_TAG\n  enabled: true\n# Checks that accessible method throw keyword is documented in KDoc\n- name: KDOC_WITHOUT_THROWS_TAG\n  enabled: true\n# Checks that KDoc is not empty\n- name: KDOC_EMPTY_KDOC\n  enabled: true\n# Checks that underscore is correctly used to split package naming\n- name: INCORRECT_PACKAGE_SEPARATOR\n  enabled: true\n# Checks that code block doesn't contain kdoc comments\n- name: COMMENTED_BY_KDOC\n  enabled: true\n# Checks that there is no @deprecated tag in kdoc\n- name: KDOC_NO_DEPRECATED_TAG\n  enabled: true\n# Checks that there is no empty content in kdoc tags\n- name: KDOC_NO_EMPTY_TAGS\n  enabled: true\n# Checks that there is only one space after kdoc tag\n- name: KDOC_WRONG_SPACES_AFTER_TAG\n  enabled: true\n# Checks tags order in kDoc. `@param`, `@return`, `@throws`\n- name: KDOC_WRONG_TAGS_ORDER\n  enabled: true\n# Checks that there is no newline of empty KDoc line (with leading asterisk) between `@param`, `@return`, `@throws` tags\n- name: KDOC_NO_NEWLINES_BETWEEN_BASIC_TAGS\n  enabled: true\n# Checks that block of tags @param, @return, @throws is separated from previous part of KDoc by exactly one empty line\n- name: KDOC_NEWLINES_BEFORE_BASIC_TAGS\n  enabled: true\n# Checks that special tags `@apiNote`, `@implNote`, `@implSpec` have exactly one empty line after\n- name: KDOC_NO_NEWLINE_AFTER_SPECIAL_TAGS\n  enabled: true\n# Checks that kdoc does not contain @author tag or date\n- name: KDOC_CONTAINS_DATE_OR_AUTHOR\n  enabled: true\n  configuration:\n    versionRegex: \\d+\\.\\d+\\.\\d+[-.\\w\\d]*\n# Checks that KDoc does not contain single line with words 'return', 'get' or 'set'\n- name: KDOC_TRIVIAL_KDOC_ON_FUNCTION\n  enabled: true\n# Checks that there is newline after header KDoc\n- name: HEADER_WRONG_FORMAT\n  enabled: true\n# Checks that file with zero or >1 classes has header KDoc\n- name: HEADER_MISSING_IN_NON_SINGLE_CLASS_FILE\n  enabled: true\n# Checks that copyright exists on top of file and is properly formatted (as a block comment)\n- name: HEADER_MISSING_OR_WRONG_COPYRIGHT\n  enabled: true\n  configuration:\n    isCopyrightMandatory: false\n    copyrightText: 'Copyright (c) Your Company Name Here. 2010-;@currYear;'\n# Checks that header kdoc is located before package directive\n- name: HEADER_NOT_BEFORE_PACKAGE\n  enabled: true\n# Checks that file does not contain lines > maxSize\n- name: FILE_IS_TOO_LONG\n  enabled: true\n  configuration:\n    # number of lines\n    maxSize: '2000'\n# Checks that file does not contain commented out code\n- name: COMMENTED_OUT_CODE\n  enabled: true\n# Checks that file does not contain only comments, imports and package directive\n- name: FILE_CONTAINS_ONLY_COMMENTS\n  enabled: true\n# Orders imports alphabetically\n- name: FILE_UNORDERED_IMPORTS\n  enabled: true\n  configuration:\n    # use logical imports grouping with sorting inside of a group\n    useRecommendedImportsOrder: true\n# Checks that general order of code parts is right\n- name: FILE_INCORRECT_BLOCKS_ORDER\n  enabled: true\n# Checks that there is exactly one line between code blocks\n- name: FILE_NO_BLANK_LINE_BETWEEN_BLOCKS\n  enabled: true\n# Checks that there is no wildcard imports. Exception: allowedWildcards\n- name: FILE_WILDCARD_IMPORTS\n  enabled: true\n  configuration:\n    allowedWildcards: \"\" # Allowed wildcards for imports (e.g. \"import com.saveourtool.diktat.*, import org.jetbrains.kotlin.*\")\n    useRecommendedImportsOrder: true\n# Checks unused imports\n- name: UNUSED_IMPORT\n  enabled: true\n  configuration:\n    deleteUnusedImport: true\n# Checks that braces are used in if, else, when, for, do, and while statements. Exception: single line ternary operator statement\n- name: NO_BRACES_IN_CONDITIONALS_AND_LOOPS\n  enabled: true\n# Checks that the declaration part of a class-like code structures (class/interface/etc.) is in the proper order\n- name: WRONG_ORDER_IN_CLASS_LIKE_STRUCTURES\n  enabled: true\n# Checks that properties with comments are separated by a blank line\n- name: BLANK_LINE_BETWEEN_PROPERTIES\n  enabled: true\n# Checks top level order\n- name: TOP_LEVEL_ORDER\n  enabled: true\n# Checks that non-empty code blocks with braces follow the K&R style (1TBS or OTBS style)\n- name: BRACES_BLOCK_STRUCTURE_ERROR\n  enabled: true\n  configuration:\n    openBraceNewline: 'True'\n    closeBraceNewline: 'True'\n# Checks that indentation is correct\n- name: WRONG_INDENTATION\n  enabled: true\n  configuration:\n    # Is newline at the end of a file needed\n    newlineAtEnd: true\n    # If true: in parameter list when parameters are split by newline they are indented with two indentations instead of one\n    extendedIndentOfParameters: false\n    # If true: if first parameter in parameter list is on the same line as opening parenthesis, then other parameters can be aligned with it\n    alignedParameters: true\n    # If true, expression bodies which begin on a separate line are indented\n    # using a continuation indent. The default is false.\n    #\n    # This flag is called CONTINUATION_INDENT_FOR_EXPRESSION_BODIES in IDEA and\n    # ij_kotlin_continuation_indent_for_expression_bodies in .editorconfig.\n    extendedIndentForExpressionBodies: false\n    # If true: if expression is split by newline after operator like +/-/`*`, then the next line is indented with two indentations instead of one\n    extendedIndentAfterOperators: true\n    # If true: when dot qualified expression starts on a new line, this line will be indented with two indentations instead of one\n    extendedIndentBeforeDot: false\n    # The indentation size for each file\n    indentationSize: 4\n# Checks that there is no empty blocks in a file.\n# If allowEmptyBlocks is true, checks that it follows correct style (have a newline)\n- name: EMPTY_BLOCK_STRUCTURE_ERROR\n  enabled: true\n  configuration:\n    # Whether a newline after `{` is required in an empty block\n    styleEmptyBlockWithNewline: 'True'\n    allowEmptyBlocks: 'False'\n# Checks that there is no more than one statement per line\n- name: MORE_THAN_ONE_STATEMENT_PER_LINE\n  enabled: true\n# Checks that the line length is < lineLength parameter\n- name: LONG_LINE\n  enabled: true\n  configuration:\n    lineLength: '120'\n# Checks that semicolons are not used at the end of a line\n- name: REDUNDANT_SEMICOLON\n  enabled: true\n# Checks that line breaks follow code style guide: rule 3.6\n- name: WRONG_NEWLINES\n  enabled: true\n  configuration:\n    # If the number of parameters on one line is more than this threshold, all parameters will be placed on separate lines.\n    maxParametersInOneLine: 2\n    # 3 by default.\n    maxCallsInOneLine: 3\n# Checks trailing comma\n- name: TRAILING_COMMA\n  enabled: true\n  configuration:\n    # VALUE_ARGUMENT\n    valueArgument: false\n    # VALUE_PARAMETER\n    valueParameter: false\n    # REFERENCE_EXPRESSION\n    indices: false\n    # WHEN_CONDITION_WITH_EXPRESSION\n    whenConditions: false\n    # STRING_TEMPLATE\n    collectionLiteral: false\n    # TYPE_PROJECTION\n    typeArgument: false\n    # TYPE_PARAMETER\n    typeParameter: false\n    # DESTRUCTURING_DECLARATION_ENTRY\n    destructuringDeclaration: false\n# Checks that there are not too many consecutive spaces in line\n- name: TOO_MANY_CONSECUTIVE_SPACES\n  enabled: true\n  configuration:\n    # Maximum allowed number of consecutive spaces (not counting indentation)\n    maxSpaces: '1'\n    # Whether formatting for enums should be kept without checking\n    saveInitialFormattingForEnums: false\n# Inspection that checks if a long dot qualified expression is used in condition or as an argument\n- name: COMPLEX_EXPRESSION\n  enabled: true\n# Checks that blank lines are used correctly.\n# For example: triggers when there are too many blank lines between function declaration\n- name: TOO_MANY_BLANK_LINES\n  enabled: true\n# Checks that usage of horizontal spaces doesn't violate code style guide\n- name: WRONG_WHITESPACE\n  enabled: true\n# Checks that backticks (``) are not used in the identifier name, except the case when it is test method (marked with @Test annotation)\n- name: BACKTICKS_PROHIBITED\n  enabled: true\n# Checks that a single line concatenation of strings is not used\n- name: STRING_CONCATENATION\n  enabled: true\n# Checks that each when statement have else in the end\n- name: WHEN_WITHOUT_ELSE\n  enabled: true\n# Checks that annotation is on a single line\n- name: ANNOTATION_NEW_LINE\n  enabled: true\n# Checks that method annotated with `Preview` annotation is private and has Preview suffix\n- name: PREVIEW_ANNOTATION\n  enabled: true\n# Checks that enum structure is correct: enum entries should be separated by comma and line break and last entry should have semicolon in the end.\n- name: ENUMS_SEPARATED\n  enabled: true\n# Checks that value on integer or float constant is not too big\n- name: LONG_NUMERICAL_VALUES_SEPARATED\n  enabled: true\n  configuration:\n    # Maximum number of digits which are not split\n    maxNumberLength: '5'\n    # Maximum number of digits between separators\n    maxBlockLength: '3'\n# Checks magic number\n- name: MAGIC_NUMBER\n  enabled: true\n  configuration:\n    # Ignore numbers from test\n    ignoreTest: \"true\"\n    # Ignore numbers\n    ignoreNumbers: \"-1, 1, 0, 2, 0U, 1U, 2U, -1L, 0L, 1L, 2L, 0UL, 1UL, 2UL\"\n    # Is ignore override hashCode function\n    ignoreHashCodeFunction: \"true\"\n    # Is ignore property\n    ignorePropertyDeclaration: \"false\"\n    # Is ignore local variable\n    ignoreLocalVariableDeclaration: \"false\"\n    # Is ignore value parameter\n    ignoreValueParameter: \"true\"\n    # Is ignore constant\n    ignoreConstantDeclaration: \"true\"\n    # Is ignore property in companion object\n    ignoreCompanionObjectPropertyDeclaration: \"true\"\n    # Is ignore numbers in enum\n    ignoreEnums: \"false\"\n    # Is ignore number in ranges\n    ignoreRanges: \"false\"\n    # Is ignore number in extension function\n    ignoreExtensionFunctions: \"false\"\n    # Is ignore number in pairs created using to\n    ignorePairsCreatedUsingTo: \"false\"\n# Checks that order of enum values or constant property inside companion is correct\n- name: WRONG_DECLARATIONS_ORDER\n  enabled: true\n  configuration:\n    # Whether enum members should be sorted alphabetically\n    sortEnum: true\n    # Whether class properties should be sorted alphabetically\n    sortProperty: true\n# Checks that multiple modifiers sequence is in the correct order\n- name: WRONG_MULTIPLE_MODIFIERS_ORDER\n  enabled: true\n# Checks that identifier has appropriate name (See table of rule 1.2 part 6)\n- name: CONFUSING_IDENTIFIER_NAMING\n  enabled: true\n# Checks year in the copyright\n- name: WRONG_COPYRIGHT_YEAR\n  enabled: true\n# Inspection that checks if local variables are declared close to the first usage site\n- name: LOCAL_VARIABLE_EARLY_DECLARATION\n  enabled: true\n# Try to avoid initialize val by null (e.g. val a: Int? = null -> val a: Int = 0)\n- name: NULLABLE_PROPERTY_TYPE\n  enabled: true\n# Inspection that checks if there is a blank line before kDoc and none after\n- name: WRONG_NEWLINES_AROUND_KDOC\n  enabled: true\n# Inspection that checks if there is no blank lines before first comment\n- name: FIRST_COMMENT_NO_BLANK_LINE\n  enabled: true\n# Inspection that checks if there are blank lines between code and comment and between code start token and comment's text\n- name: COMMENT_WHITE_SPACE\n  enabled: true\n  configuration:\n    maxSpacesBeforeComment: 2\n    maxSpacesInComment: 1\n# Inspection that checks if all comment's are inside if-else code blocks. Exception is general if comment\n- name: IF_ELSE_COMMENTS\n  enabled: true\n# Type aliases provide alternative names for existing types when type's reference text is longer 25 chars\n- name: TYPE_ALIAS\n  enabled: true\n  configuration:\n    typeReferenceLength: '25' # max length of type reference\n# Checks if casting can be omitted\n- name: SMART_CAST_NEEDED\n  enabled: true\n# Checks that variables of generic types have explicit type declaration\n- name: GENERIC_VARIABLE_WRONG_DECLARATION\n  enabled: true\n# Inspection that checks if string template has redundant curly braces\n- name: STRING_TEMPLATE_CURLY_BRACES\n  enabled: true\n# Variables with `val` modifier - are immutable (read-only). Usage of such variables instead of `var` variables increases\n# robustness and readability of code, because `var` variables can be reassigned several times in the business logic.\n# This rule prohibits usage of `var`s as local variables - the only exception is accumulators and counters\n- name: SAY_NO_TO_VAR\n  enabled: true\n# Inspection that checks if string template has redundant quotes\n- name: STRING_TEMPLATE_QUOTES\n  enabled: true\n# Check if there are redundant nested if-statements, which could be collapsed into a single one by concatenating their conditions\n- name: COLLAPSE_IF_STATEMENTS\n  enabled: true\n  configuration:\n    startCollapseFromNestedLevel: 2\n# Checks that floating-point values are not used in arithmetic expressions\n- name: FLOAT_IN_ACCURATE_CALCULATIONS\n  enabled: true\n# Checks that function length isn't too long\n- name: TOO_LONG_FUNCTION\n  enabled: true\n  configuration:\n    maxFunctionLength: '30' # max length of function\n    isIncludeHeader: 'false' # count function's header\n# Warns if there are nested functions\n- name: AVOID_NESTED_FUNCTIONS\n  enabled: true\n# Checks that lambda inside function parameters is in the end\n- name: LAMBDA_IS_NOT_LAST_PARAMETER\n  enabled: true\n# Checks that function doesn't contains too many parameters\n- name: TOO_MANY_PARAMETERS\n  enabled: true\n  configuration:\n    maxParameterListSize: '5' # max parameters size\n# Checks that function doesn't have too many nested blocks\n- name: NESTED_BLOCK\n  enabled: true\n  configuration:\n    maxNestedBlockQuantity: '4'\n# Checks that function use default values, instead overloading\n- name: WRONG_OVERLOADING_FUNCTION_ARGUMENTS\n  enabled: true\n# Checks that using runBlocking inside async block code\n- name: RUN_BLOCKING_INSIDE_ASYNC\n  enabled: true\n# Checks that property in constructor doesn't contain comment\n- name: KDOC_NO_CONSTRUCTOR_PROPERTY\n  enabled: true\n  configuration:\n    isParamTagsForParameters: true # create param tags for parameters without val or var\n    isParamTagsForPrivateProperties: true # create param tags for private properties\n    isParamTagsForGenericTypes: true # create param tags for generic types\n# Checks that the long lambda has parameters\n- name: TOO_MANY_LINES_IN_LAMBDA\n  enabled: true\n  configuration:\n    maxLambdaLength: 10 # max length of lambda without parameters\n# Checks that using unnecessary, custom label\n- name: CUSTOM_LABEL\n  enabled: true\n# Check that lambda with inner lambda doesn't use implicit parameter\n- name: PARAMETER_NAME_IN_OUTER_LAMBDA\n  enabled: true\n# Checks that property in KDoc present in class\n- name: KDOC_EXTRA_PROPERTY\n  enabled: true\n# There's a property in KDoc which is already present\n- name: KDOC_DUPLICATE_PROPERTY\n  enabled: true\n# Checks that KDoc in constructor has property tag but with comment inside constructor\n- name: KDOC_NO_CONSTRUCTOR_PROPERTY_WITH_COMMENT\n  enabled: true\n# if a class has single constructor, it should be converted to a primary constructor\n- name: SINGLE_CONSTRUCTOR_SHOULD_BE_PRIMARY\n  enabled: true\n# Checks if class can be made as data class\n- name: USE_DATA_CLASS\n  enabled: true\n# Checks that never use the name of a variable in the custom getter or setter\n- name: WRONG_NAME_OF_VARIABLE_INSIDE_ACCESSOR\n  enabled: true\n# Checks that classes have only one init block\n- name: MULTIPLE_INIT_BLOCKS\n  enabled: true\n# Checks that there are abstract functions in abstract class\n- name: CLASS_SHOULD_NOT_BE_ABSTRACT\n  enabled: true\n# Checks if there are any trivial getters or setters\n- name: TRIVIAL_ACCESSORS_ARE_NOT_RECOMMENDED\n  enabled: true\n# Checks that no custom getters and setters are used for properties. It is a more wide rule than TRIVIAL_ACCESSORS_ARE_NOT_RECOMMENDED\n# Kotlin compiler automatically generates `get` and `set` methods for properties and also lets the possibility to override it.\n# But in all cases it is very confusing when `get` and `set` are overridden for a developer who uses this particular class.\n# Developer expects to get the value of the property, but receives some unknown value and some extra side effect hidden by the custom getter/setter.\n# Use extra functions for it instead.\n- name: CUSTOM_GETTERS_SETTERS\n  enabled: true\n# Checks if null-check was used explicitly (for example: if (a == null))\n# Try to avoid explicit null checks (explicit comparison with `null`)\n# Kotlin is declared as [Null-safe](https://kotlinlang.org/docs/reference/null-safety.html) language.\n# But Kotlin architects wanted Kotlin to be fully compatible with Java, that's why `null` keyword was also introduced in Kotlin.\n# There are several code-structures that can be used in Kotlin to avoid null-checks. For example: `?:`,  `.let {}`, `.also {}`, e.t.c\n- name: AVOID_NULL_CHECKS\n  enabled: true\n# Checks if class instantiation can be wrapped in `apply` for better readability\n- name: COMPACT_OBJECT_INITIALIZATION\n  enabled: true\n# Checks explicit supertype qualification\n- name: USELESS_SUPERTYPE\n  enabled: true\n# Checks if extension function with the same signature don't have related classes\n- name: EXTENSION_FUNCTION_SAME_SIGNATURE\n  enabled: true\n# Checks if there is empty primary constructor\n- name: EMPTY_PRIMARY_CONSTRUCTOR\n  enabled: true\n# In case of not using field keyword in property accessors,\n# there should be explicit backing property with the name of real property\n# Example: val table get() {if (_table == null) ...} -> table should have _table\n- name: NO_CORRESPONDING_PROPERTY\n  enabled: true\n# Checks if there is class/object that can be replace with extension function\n- name: AVOID_USING_UTILITY_CLASS\n  enabled: true\n# If there is stateless class it is preferred to use object\n- name: OBJECT_IS_PREFERRED\n  enabled: true\n# If there exists negated version of function you should prefer it instead of !functionCall\n- name: INVERSE_FUNCTION_PREFERRED\n  enabled: true\n# Checks if class can be converted to inline class\n- name: INLINE_CLASS_CAN_BE_USED\n  enabled: true\n# If file contains class, then it can't contain extension functions for the same class\n- name: EXTENSION_FUNCTION_WITH_CLASS\n  enabled: true\n# Check if kts script contains other functions except run code\n- name: RUN_IN_SCRIPT\n  enabled: true\n# Check if boolean expression can be simplified\n- name: COMPLEX_BOOLEAN_EXPRESSION\n  enabled: true\n# Check if range can replace with until or `rangeTo` function with range\n- name: CONVENTIONAL_RANGE\n  enabled: true\n  configuration:\n    isRangeToIgnore: false\n# Check if there is a call of print()\\println() or console.log(). Assumption that it's a debug print\n- name: DEBUG_PRINT\n  enabled: true\n# Check that typealias name is in PascalCase\n- name: TYPEALIAS_NAME_INCORRECT_CASE\n  enabled: true\n# Should change property length - 1 to property lastIndex\n- name: USE_LAST_INDEX\n  enabled: true\n# Only properties from the primary constructor should be documented in a @property tag in class KDoc\n- name: KDOC_NO_CLASS_BODY_PROPERTIES_IN_HEADER\n  enabled: true\n"
  },
  {
    "path": "examples/gradle-groovy-dsl/src/main/kotlin/AnotherTest.kt",
    "content": "package whate.ver\n\nfun String.createPluginConfig() {\n    val pluginConfig = TomlDecoder.decode<T>(\n        serializer(),\n        fakeFileNode,\n        DecoderConf()\n    )\n    pluginConfig.configLocation = this.toPath()\n    pluginConfig.prop1 = property1\n    // comment1\n    pluginConfig.configLocation2 = this.toPath()\n    // comment2\n    pluginConfig.prop2 = property2\n}\n"
  },
  {
    "path": "examples/gradle-groovy-dsl/src/main/kotlin/Test.kt",
    "content": "package incorrect\n\nclass incorrectname: Exception() {\n    fun INCORRECT_FUNCTION() {\n        throw Exception()\n    }\n\n    // fun myCommentedFunction() {\n    // }\n\n    val Incorrect_Val = 5\n\n}\n"
  },
  {
    "path": "examples/gradle-kotlin-dsl/build.gradle.kts",
    "content": "plugins {\n    id(\"com.saveourtool.diktat\") version \"2.0.0\"\n}\n\nrepositories {\n    mavenCentral()\n}\n\ndiktat {\n    inputs { include(\"src/**/*.kt\") }\n}\n"
  },
  {
    "path": "examples/gradle-kotlin-dsl/diktat-analysis.yml",
    "content": "# Common configuration\n- name: DIKTAT_COMMON\n  configuration:\n    # put your package name here - it will be autofixed and checked\n    domainName: your.name.here\n    testDirs: test\n    # expected values:  disabledChapters: \"Naming, Comments, General, Variables, Functions, Classes\"\n    # or: \"1, 2, 3, 4, 5, 6\"\n    disabledChapters: \"\"\n    kotlinVersion: 2.1\n    srcDirectories: \"main\"\n# Checks that the Class/Enum/Interface name matches Pascal case\n- name: CLASS_NAME_INCORRECT\n  enabled: true\n  # all code blocks with MyAnnotation will be ignored and not checked\n  ignoreAnnotated: [ MyAnnotation ]\n# Checks that CONSTANT (treated as const val from companion object or class level) is in non UPPER_SNAKE_CASE\n- name: CONSTANT_UPPERCASE\n  enabled: true\n# Checks that enum value is in upper SNAKE_CASE or in PascalCase depending on the config. UPPER_SNAKE_CASE is the default, but can be changed by 'enumStyle' config\n- name: ENUM_VALUE\n  enabled: true\n  configuration:\n    # Two options: SNAKE_CASE (default), PascalCase\n    enumStyle: SNAKE_CASE\n# Checks that class which extends any Exception class has Exception suffix\n- name: EXCEPTION_SUFFIX\n  enabled: true\n# Checks that file name has extension\n- name: FILE_NAME_INCORRECT\n  enabled: true\n# Checks that file name matches class name, if it is only one class in file\n- name: FILE_NAME_MATCH_CLASS\n  enabled: true\n# Checks that functions/methods which return boolean have special prefix like \"is/should/e.t.c\"\n- name: FUNCTION_BOOLEAN_PREFIX\n  enabled: true\n  configuration:\n    allowedPrefixes: \"\" # A list of functions that return boolean and are allowed to use. Input is in a form \"foo, bar\".\n# Checks that function/method name is in lowerCamelCase\n- name: FUNCTION_NAME_INCORRECT_CASE\n  enabled: true\n# Checks that typealias name is in PascalCase\n- name: TYPEALIAS_NAME_INCORRECT_CASE\n  enabled: true\n# Checks that generic name doesn't contain more than 1 letter (capital). It can be followed by numbers, example: T12, T\n- name: GENERIC_NAME\n  enabled: true\n# Identifier length should be in range [2,64] except names that used in industry like {i, j} and 'e' for catching exceptions\n- name: IDENTIFIER_LENGTH\n  enabled: true\n# Checks that the object matches PascalCase\n- name: OBJECT_NAME_INCORRECT\n  enabled: true\n# Checks that package name is in correct (lower) case\n- name: PACKAGE_NAME_INCORRECT_CASE\n  enabled: true\n# Checks that package name starts with the company's domain\n- name: PACKAGE_NAME_INCORRECT_PREFIX\n  enabled: false\n# Checks that package name does not have incorrect symbols like underscore or non-ASCII letters/digits\n- name: PACKAGE_NAME_INCORRECT_SYMBOLS\n  enabled: true\n# Checks that the path for a file matches with a package name\n- name: PACKAGE_NAME_INCORRECT_PATH\n  enabled: false\n# Checks that package name is in the file\n- name: PACKAGE_NAME_MISSING\n  enabled: true\n# Checks that variable does not have prefix (like mVariable or M_VARIABLE)\n- name: VARIABLE_HAS_PREFIX\n  enabled: true\n# Checks that variable does not contain one single letter, only exceptions are fixed names that used in industry like {i, j}\n- name: VARIABLE_NAME_INCORRECT\n  enabled: true\n# Checks that the name of variable is in lowerCamelCase and contains only ASCII letters\n- name: VARIABLE_NAME_INCORRECT_FORMAT\n  enabled: true\n# Checks that functions have kdoc\n- name: MISSING_KDOC_ON_FUNCTION\n  enabled: true\n# Checks that on file level internal or public class or function has missing KDoc\n- name: MISSING_KDOC_TOP_LEVEL\n  enabled: true\n# Checks that accessible internal elements (protected, public, internal) in a class are documented\n- name: MISSING_KDOC_CLASS_ELEMENTS\n  enabled: true\n# Checks that accessible method parameters are documented in KDoc\n- name: KDOC_WITHOUT_PARAM_TAG\n  enabled: true\n# Checks that accessible method explicit return type is documented in KDoc\n- name: KDOC_WITHOUT_RETURN_TAG\n  enabled: true\n# Checks that accessible method throw keyword is documented in KDoc\n- name: KDOC_WITHOUT_THROWS_TAG\n  enabled: true\n# Checks that KDoc is not empty\n- name: KDOC_EMPTY_KDOC\n  enabled: true\n# Checks that underscore is correctly used to split package naming\n- name: INCORRECT_PACKAGE_SEPARATOR\n  enabled: true\n# Checks that code block doesn't contain kdoc comments\n- name: COMMENTED_BY_KDOC\n  enabled: true\n# Checks that there is no @deprecated tag in kdoc\n- name: KDOC_NO_DEPRECATED_TAG\n  enabled: true\n# Checks that there is no empty content in kdoc tags\n- name: KDOC_NO_EMPTY_TAGS\n  enabled: true\n# Checks that there is only one space after kdoc tag\n- name: KDOC_WRONG_SPACES_AFTER_TAG\n  enabled: true\n# Checks tags order in kDoc. `@param`, `@return`, `@throws`\n- name: KDOC_WRONG_TAGS_ORDER\n  enabled: true\n# Checks that there is no newline of empty KDoc line (with leading asterisk) between `@param`, `@return`, `@throws` tags\n- name: KDOC_NO_NEWLINES_BETWEEN_BASIC_TAGS\n  enabled: true\n# Checks that block of tags @param, @return, @throws is separated from previous part of KDoc by exactly one empty line\n- name: KDOC_NEWLINES_BEFORE_BASIC_TAGS\n  enabled: true\n# Checks that special tags `@apiNote`, `@implNote`, `@implSpec` have exactly one empty line after\n- name: KDOC_NO_NEWLINE_AFTER_SPECIAL_TAGS\n  enabled: true\n# Checks that kdoc does not contain @author tag or date\n- name: KDOC_CONTAINS_DATE_OR_AUTHOR\n  enabled: true\n  configuration:\n    versionRegex: \\d+\\.\\d+\\.\\d+[-.\\w\\d]*\n# Checks that KDoc does not contain single line with words 'return', 'get' or 'set'\n- name: KDOC_TRIVIAL_KDOC_ON_FUNCTION\n  enabled: true\n# Checks that there is newline after header KDoc\n- name: HEADER_WRONG_FORMAT\n  enabled: true\n# Checks that file with zero or >1 classes has header KDoc\n- name: HEADER_MISSING_IN_NON_SINGLE_CLASS_FILE\n  enabled: true\n# Checks that copyright exists on top of file and is properly formatted (as a block comment)\n- name: HEADER_MISSING_OR_WRONG_COPYRIGHT\n  enabled: true\n  configuration:\n    isCopyrightMandatory: false\n    copyrightText: 'Copyright (c) Your Company Name Here. 2010-;@currYear;'\n# Checks that header kdoc is located before package directive\n- name: HEADER_NOT_BEFORE_PACKAGE\n  enabled: true\n# Checks that file does not contain lines > maxSize\n- name: FILE_IS_TOO_LONG\n  enabled: true\n  configuration:\n    # number of lines\n    maxSize: '2000'\n# Checks that file does not contain commented out code\n- name: COMMENTED_OUT_CODE\n  enabled: true\n# Checks that file does not contain only comments, imports and package directive\n- name: FILE_CONTAINS_ONLY_COMMENTS\n  enabled: true\n# Orders imports alphabetically\n- name: FILE_UNORDERED_IMPORTS\n  enabled: true\n  configuration:\n    # use logical imports grouping with sorting inside of a group\n    useRecommendedImportsOrder: true\n# Checks that general order of code parts is right\n- name: FILE_INCORRECT_BLOCKS_ORDER\n  enabled: true\n# Checks that there is exactly one line between code blocks\n- name: FILE_NO_BLANK_LINE_BETWEEN_BLOCKS\n  enabled: true\n# Checks that there is no wildcard imports. Exception: allowedWildcards\n- name: FILE_WILDCARD_IMPORTS\n  enabled: true\n  configuration:\n    allowedWildcards: \"\" # Allowed wildcards for imports (e.g. \"import com.saveourtool.diktat.*, import org.jetbrains.kotlin.*\")\n    useRecommendedImportsOrder: true\n# Checks unused imports\n- name: UNUSED_IMPORT\n  enabled: true\n  configuration:\n    deleteUnusedImport: true\n# Checks that braces are used in if, else, when, for, do, and while statements. Exception: single line ternary operator statement\n- name: NO_BRACES_IN_CONDITIONALS_AND_LOOPS\n  enabled: true\n# Checks that the declaration part of a class-like code structures (class/interface/etc.) is in the proper order\n- name: WRONG_ORDER_IN_CLASS_LIKE_STRUCTURES\n  enabled: true\n# Checks that properties with comments are separated by a blank line\n- name: BLANK_LINE_BETWEEN_PROPERTIES\n  enabled: true\n# Checks top level order\n- name: TOP_LEVEL_ORDER\n  enabled: true\n# Checks that non-empty code blocks with braces follow the K&R style (1TBS or OTBS style)\n- name: BRACES_BLOCK_STRUCTURE_ERROR\n  enabled: true\n  configuration:\n    openBraceNewline: 'True'\n    closeBraceNewline: 'True'\n# Checks that indentation is correct\n- name: WRONG_INDENTATION\n  enabled: true\n  configuration:\n    # Is newline at the end of a file needed\n    newlineAtEnd: true\n    # If true: in parameter list when parameters are split by newline they are indented with two indentations instead of one\n    extendedIndentOfParameters: false\n    # If true: if first parameter in parameter list is on the same line as opening parenthesis, then other parameters can be aligned with it\n    alignedParameters: true\n    # If true, expression bodies which begin on a separate line are indented\n    # using a continuation indent. The default is false.\n    #\n    # This flag is called CONTINUATION_INDENT_FOR_EXPRESSION_BODIES in IDEA and\n    # ij_kotlin_continuation_indent_for_expression_bodies in .editorconfig.\n    extendedIndentForExpressionBodies: false\n    # If true: if expression is split by newline after operator like +/-/`*`, then the next line is indented with two indentations instead of one\n    extendedIndentAfterOperators: true\n    # If true: when dot qualified expression starts on a new line, this line will be indented with two indentations instead of one\n    extendedIndentBeforeDot: false\n    # The indentation size for each file\n    indentationSize: 4\n# Checks that there is no empty blocks in a file.\n# If allowEmptyBlocks is true, checks that it follows correct style (have a newline)\n- name: EMPTY_BLOCK_STRUCTURE_ERROR\n  enabled: true\n  configuration:\n    # Whether a newline after `{` is required in an empty block\n    styleEmptyBlockWithNewline: 'True'\n    allowEmptyBlocks: 'False'\n# Checks that there is no more than one statement per line\n- name: MORE_THAN_ONE_STATEMENT_PER_LINE\n  enabled: true\n# Checks that the line length is < lineLength parameter\n- name: LONG_LINE\n  enabled: true\n  configuration:\n    lineLength: '120'\n# Checks that semicolons are not used at the end of a line\n- name: REDUNDANT_SEMICOLON\n  enabled: true\n# Checks that line breaks follow code style guide: rule 3.6\n- name: WRONG_NEWLINES\n  enabled: true\n  configuration:\n    # If the number of parameters on one line is more than this threshold, all parameters will be placed on separate lines.\n    maxParametersInOneLine: 2\n    # 3 by default.\n    maxCallsInOneLine: 3\n# Checks trailing comma\n- name: TRAILING_COMMA\n  enabled: true\n  configuration:\n    # VALUE_ARGUMENT\n    valueArgument: false\n    # VALUE_PARAMETER\n    valueParameter: false\n    # REFERENCE_EXPRESSION\n    indices: false\n    # WHEN_CONDITION_WITH_EXPRESSION\n    whenConditions: false\n    # STRING_TEMPLATE\n    collectionLiteral: false\n    # TYPE_PROJECTION\n    typeArgument: false\n    # TYPE_PARAMETER\n    typeParameter: false\n    # DESTRUCTURING_DECLARATION_ENTRY\n    destructuringDeclaration: false\n# Checks that there are not too many consecutive spaces in line\n- name: TOO_MANY_CONSECUTIVE_SPACES\n  enabled: true\n  configuration:\n    # Maximum allowed number of consecutive spaces (not counting indentation)\n    maxSpaces: '1'\n    # Whether formatting for enums should be kept without checking\n    saveInitialFormattingForEnums: false\n# Inspection that checks if a long dot qualified expression is used in condition or as an argument\n- name: COMPLEX_EXPRESSION\n  enabled: true\n# Checks that blank lines are used correctly.\n# For example: triggers when there are too many blank lines between function declaration\n- name: TOO_MANY_BLANK_LINES\n  enabled: true\n# Checks that usage of horizontal spaces doesn't violate code style guide\n- name: WRONG_WHITESPACE\n  enabled: true\n# Checks that backticks (``) are not used in the identifier name, except the case when it is test method (marked with @Test annotation)\n- name: BACKTICKS_PROHIBITED\n  enabled: true\n# Checks that a single line concatenation of strings is not used\n- name: STRING_CONCATENATION\n  enabled: true\n# Checks that each when statement have else in the end\n- name: WHEN_WITHOUT_ELSE\n  enabled: true\n# Checks that annotation is on a single line\n- name: ANNOTATION_NEW_LINE\n  enabled: true\n# Checks that method annotated with `Preview` annotation is private and has Preview suffix\n- name: PREVIEW_ANNOTATION\n  enabled: true\n# Checks that enum structure is correct: enum entries should be separated by comma and line break and last entry should have semicolon in the end.\n- name: ENUMS_SEPARATED\n  enabled: true\n# Checks that value on integer or float constant is not too big\n- name: LONG_NUMERICAL_VALUES_SEPARATED\n  enabled: true\n  configuration:\n    # Maximum number of digits which are not split\n    maxNumberLength: '5'\n    # Maximum number of digits between separators\n    maxBlockLength: '3'\n# Checks magic number\n- name: MAGIC_NUMBER\n  enabled: true\n  configuration:\n    # Ignore numbers from test\n    ignoreTest: \"true\"\n    # Ignore numbers\n    ignoreNumbers: \"-1, 1, 0, 2, 0U, 1U, 2U, -1L, 0L, 1L, 2L, 0UL, 1UL, 2UL\"\n    # Is ignore override hashCode function\n    ignoreHashCodeFunction: \"true\"\n    # Is ignore property\n    ignorePropertyDeclaration: \"false\"\n    # Is ignore local variable\n    ignoreLocalVariableDeclaration: \"false\"\n    # Is ignore value parameter\n    ignoreValueParameter: \"true\"\n    # Is ignore constant\n    ignoreConstantDeclaration: \"true\"\n    # Is ignore property in companion object\n    ignoreCompanionObjectPropertyDeclaration: \"true\"\n    # Is ignore numbers in enum\n    ignoreEnums: \"false\"\n    # Is ignore number in ranges\n    ignoreRanges: \"false\"\n    # Is ignore number in extension function\n    ignoreExtensionFunctions: \"false\"\n    # Is ignore number in pairs created using to\n    ignorePairsCreatedUsingTo: \"false\"\n# Checks that order of enum values or constant property inside companion is correct\n- name: WRONG_DECLARATIONS_ORDER\n  enabled: true\n  configuration:\n    # Whether enum members should be sorted alphabetically\n    sortEnum: true\n    # Whether class properties should be sorted alphabetically\n    sortProperty: true\n# Checks that multiple modifiers sequence is in the correct order\n- name: WRONG_MULTIPLE_MODIFIERS_ORDER\n  enabled: true\n# Checks that identifier has appropriate name (See table of rule 1.2 part 6)\n- name: CONFUSING_IDENTIFIER_NAMING\n  enabled: true\n# Checks year in the copyright\n- name: WRONG_COPYRIGHT_YEAR\n  enabled: true\n# Inspection that checks if local variables are declared close to the first usage site\n- name: LOCAL_VARIABLE_EARLY_DECLARATION\n  enabled: true\n# Try to avoid initialize val by null (e.g. val a: Int? = null -> val a: Int = 0)\n- name: NULLABLE_PROPERTY_TYPE\n  enabled: true\n# Inspection that checks if there is a blank line before kDoc and none after\n- name: WRONG_NEWLINES_AROUND_KDOC\n  enabled: true\n# Inspection that checks if there is no blank lines before first comment\n- name: FIRST_COMMENT_NO_BLANK_LINE\n  enabled: true\n# Inspection that checks if there are blank lines between code and comment and between code start token and comment's text\n- name: COMMENT_WHITE_SPACE\n  enabled: true\n  configuration:\n    maxSpacesBeforeComment: 2\n    maxSpacesInComment: 1\n# Inspection that checks if all comment's are inside if-else code blocks. Exception is general if comment\n- name: IF_ELSE_COMMENTS\n  enabled: true\n# Type aliases provide alternative names for existing types when type's reference text is longer 25 chars\n- name: TYPE_ALIAS\n  enabled: true\n  configuration:\n    typeReferenceLength: '25' # max length of type reference\n# Checks if casting can be omitted\n- name: SMART_CAST_NEEDED\n  enabled: true\n# Checks that variables of generic types have explicit type declaration\n- name: GENERIC_VARIABLE_WRONG_DECLARATION\n  enabled: true\n# Inspection that checks if string template has redundant curly braces\n- name: STRING_TEMPLATE_CURLY_BRACES\n  enabled: true\n# Variables with `val` modifier - are immutable (read-only). Usage of such variables instead of `var` variables increases\n# robustness and readability of code, because `var` variables can be reassigned several times in the business logic.\n# This rule prohibits usage of `var`s as local variables - the only exception is accumulators and counters\n- name: SAY_NO_TO_VAR\n  enabled: true\n# Inspection that checks if string template has redundant quotes\n- name: STRING_TEMPLATE_QUOTES\n  enabled: true\n# Check if there are redundant nested if-statements, which could be collapsed into a single one by concatenating their conditions\n- name: COLLAPSE_IF_STATEMENTS\n  enabled: true\n  configuration:\n    startCollapseFromNestedLevel: 2\n# Checks that floating-point values are not used in arithmetic expressions\n- name: FLOAT_IN_ACCURATE_CALCULATIONS\n  enabled: true\n# Checks that function length isn't too long\n- name: TOO_LONG_FUNCTION\n  enabled: true\n  configuration:\n    maxFunctionLength: '30' # max length of function\n    isIncludeHeader: 'false' # count function's header\n# Warns if there are nested functions\n- name: AVOID_NESTED_FUNCTIONS\n  enabled: true\n# Checks that lambda inside function parameters is in the end\n- name: LAMBDA_IS_NOT_LAST_PARAMETER\n  enabled: true\n# Checks that function doesn't contains too many parameters\n- name: TOO_MANY_PARAMETERS\n  enabled: true\n  configuration:\n    maxParameterListSize: '5' # max parameters size\n# Checks that function doesn't have too many nested blocks\n- name: NESTED_BLOCK\n  enabled: true\n  configuration:\n    maxNestedBlockQuantity: '4'\n# Checks that function use default values, instead overloading\n- name: WRONG_OVERLOADING_FUNCTION_ARGUMENTS\n  enabled: true\n# Checks that using runBlocking inside async block code\n- name: RUN_BLOCKING_INSIDE_ASYNC\n  enabled: true\n# Checks that property in constructor doesn't contain comment\n- name: KDOC_NO_CONSTRUCTOR_PROPERTY\n  enabled: true\n  configuration:\n    isParamTagsForParameters: true # create param tags for parameters without val or var\n    isParamTagsForPrivateProperties: true # create param tags for private properties\n    isParamTagsForGenericTypes: true # create param tags for generic types\n# Checks that the long lambda has parameters\n- name: TOO_MANY_LINES_IN_LAMBDA\n  enabled: true\n  configuration:\n    maxLambdaLength: 10 # max length of lambda without parameters\n# Checks that using unnecessary, custom label\n- name: CUSTOM_LABEL\n  enabled: true\n# Check that lambda with inner lambda doesn't use implicit parameter\n- name: PARAMETER_NAME_IN_OUTER_LAMBDA\n  enabled: true\n# Checks that property in KDoc present in class\n- name: KDOC_EXTRA_PROPERTY\n  enabled: true\n# There's a property in KDoc which is already present\n- name: KDOC_DUPLICATE_PROPERTY\n  enabled: true\n# Checks that KDoc in constructor has property tag but with comment inside constructor\n- name: KDOC_NO_CONSTRUCTOR_PROPERTY_WITH_COMMENT\n  enabled: true\n# if a class has single constructor, it should be converted to a primary constructor\n- name: SINGLE_CONSTRUCTOR_SHOULD_BE_PRIMARY\n  enabled: true\n# Checks if class can be made as data class\n- name: USE_DATA_CLASS\n  enabled: true\n# Checks that never use the name of a variable in the custom getter or setter\n- name: WRONG_NAME_OF_VARIABLE_INSIDE_ACCESSOR\n  enabled: true\n# Checks that classes have only one init block\n- name: MULTIPLE_INIT_BLOCKS\n  enabled: true\n# Checks that there are abstract functions in abstract class\n- name: CLASS_SHOULD_NOT_BE_ABSTRACT\n  enabled: true\n# Checks if there are any trivial getters or setters\n- name: TRIVIAL_ACCESSORS_ARE_NOT_RECOMMENDED\n  enabled: true\n# Checks that no custom getters and setters are used for properties. It is a more wide rule than TRIVIAL_ACCESSORS_ARE_NOT_RECOMMENDED\n# Kotlin compiler automatically generates `get` and `set` methods for properties and also lets the possibility to override it.\n# But in all cases it is very confusing when `get` and `set` are overridden for a developer who uses this particular class.\n# Developer expects to get the value of the property, but receives some unknown value and some extra side effect hidden by the custom getter/setter.\n# Use extra functions for it instead.\n- name: CUSTOM_GETTERS_SETTERS\n  enabled: true\n# Checks if null-check was used explicitly (for example: if (a == null))\n# Try to avoid explicit null checks (explicit comparison with `null`)\n# Kotlin is declared as [Null-safe](https://kotlinlang.org/docs/reference/null-safety.html) language.\n# But Kotlin architects wanted Kotlin to be fully compatible with Java, that's why `null` keyword was also introduced in Kotlin.\n# There are several code-structures that can be used in Kotlin to avoid null-checks. For example: `?:`,  `.let {}`, `.also {}`, e.t.c\n- name: AVOID_NULL_CHECKS\n  enabled: true\n# Checks if class instantiation can be wrapped in `apply` for better readability\n- name: COMPACT_OBJECT_INITIALIZATION\n  enabled: true\n# Checks explicit supertype qualification\n- name: USELESS_SUPERTYPE\n  enabled: true\n# Checks if extension function with the same signature don't have related classes\n- name: EXTENSION_FUNCTION_SAME_SIGNATURE\n  enabled: true\n# Checks if there is empty primary constructor\n- name: EMPTY_PRIMARY_CONSTRUCTOR\n  enabled: true\n# In case of not using field keyword in property accessors,\n# there should be explicit backing property with the name of real property\n# Example: val table get() {if (_table == null) ...} -> table should have _table\n- name: NO_CORRESPONDING_PROPERTY\n  enabled: true\n# Checks if there is class/object that can be replace with extension function\n- name: AVOID_USING_UTILITY_CLASS\n  enabled: true\n# If there is stateless class it is preferred to use object\n- name: OBJECT_IS_PREFERRED\n  enabled: true\n# If there exists negated version of function you should prefer it instead of !functionCall\n- name: INVERSE_FUNCTION_PREFERRED\n  enabled: true\n# Checks if class can be converted to inline class\n- name: INLINE_CLASS_CAN_BE_USED\n  enabled: true\n# If file contains class, then it can't contain extension functions for the same class\n- name: EXTENSION_FUNCTION_WITH_CLASS\n  enabled: true\n# Check if kts script contains other functions except run code\n- name: RUN_IN_SCRIPT\n  enabled: true\n# Check if boolean expression can be simplified\n- name: COMPLEX_BOOLEAN_EXPRESSION\n  enabled: true\n# Check if range can replace with until or `rangeTo` function with range\n- name: CONVENTIONAL_RANGE\n  enabled: true\n  configuration:\n    isRangeToIgnore: false\n# Check if there is a call of print()\\println() or console.log(). Assumption that it's a debug print\n- name: DEBUG_PRINT\n  enabled: true\n# Check that typealias name is in PascalCase\n- name: TYPEALIAS_NAME_INCORRECT_CASE\n  enabled: true\n# Should change property length - 1 to property lastIndex\n- name: USE_LAST_INDEX\n  enabled: true\n# Only properties from the primary constructor should be documented in a @property tag in class KDoc\n- name: KDOC_NO_CLASS_BODY_PROPERTIES_IN_HEADER\n  enabled: true\n"
  },
  {
    "path": "examples/gradle-kotlin-dsl/settings.gradle.kts",
    "content": ""
  },
  {
    "path": "examples/gradle-kotlin-dsl/src/main/kotlin/AnotherTest.kt",
    "content": "package whate.ver\n\nfun String.createPluginConfig() {\n    val pluginConfig = TomlDecoder.decode<T>(\n        serializer(),\n        fakeFileNode,\n        DecoderConf()\n    )\n    pluginConfig.configLocation = this.toPath()\n    pluginConfig.prop1 = property1\n    // comment1\n    pluginConfig.configLocation2 = this.toPath()\n    // comment2\n    pluginConfig.prop2 = property2\n}\n"
  },
  {
    "path": "examples/gradle-kotlin-dsl/src/main/kotlin/Test.kt",
    "content": "package incorrect\n\nclass incorrectname: Exception() {\n    fun INCORRECT_FUNCTION() {\n        throw Exception()\n    }\n\n    // fun myCommentedFunction() {\n    // }\n\n    val Incorrect_Val = 5\n\n}\n"
  },
  {
    "path": "examples/gradle-kotlin-dsl-multiproject/backend/build.gradle.kts",
    "content": "plugins {\n    kotlin(\"jvm\")\n}\n"
  },
  {
    "path": "examples/gradle-kotlin-dsl-multiproject/backend/src/main/kotlin/Test.kt",
    "content": "package incorrect\n\nclass incorrectname: Exception() {\n    fun INCORRECT_FUNCTION() {\n        throw Exception()\n    }\n\n    // fun myCommentedFunction() {\n    // }\n\n    val Incorrect_Val = 5\n\n}\n"
  },
  {
    "path": "examples/gradle-kotlin-dsl-multiproject/build.gradle.kts",
    "content": "import com.saveourtool.diktat.plugin.gradle.DiktatExtension\nimport com.saveourtool.diktat.plugin.gradle.DiktatGradlePlugin\n\nplugins {\n    kotlin(\"jvm\") version \"2.1.0\"\n    id(\"com.saveourtool.diktat\") version \"2.0.0\" apply false\n}\n\nallprojects {\n    repositories {\n        mavenLocal()\n        mavenCentral()\n    }\n    apply<DiktatGradlePlugin>()\n    configure<DiktatExtension> {\n        diktatConfigFile = rootProject.file(\"diktat-analysis.yml\")\n        inputs { include(\"src/**/*.kt\") }\n        debug = true\n    }\n}\n"
  },
  {
    "path": "examples/gradle-kotlin-dsl-multiproject/diktat-analysis.yml",
    "content": "# Common configuration\n- name: DIKTAT_COMMON\n  configuration:\n    # put your package name here - it will be autofixed and checked\n    domainName: your.name.here\n    testDirs: test\n    # expected values:  disabledChapters: \"Naming, Comments, General, Variables, Functions, Classes\"\n    # or: \"1, 2, 3, 4, 5, 6\"\n    disabledChapters: \"\"\n    kotlinVersion: 2.1\n    srcDirectories: \"main\"\n# Checks that the Class/Enum/Interface name matches Pascal case\n- name: CLASS_NAME_INCORRECT\n  enabled: true\n  # all code blocks with MyAnnotation will be ignored and not checked\n  ignoreAnnotated: [ MyAnnotation ]\n# Checks that CONSTANT (treated as const val from companion object or class level) is in non UPPER_SNAKE_CASE\n- name: CONSTANT_UPPERCASE\n  enabled: true\n# Checks that enum value is in upper SNAKE_CASE or in PascalCase depending on the config. UPPER_SNAKE_CASE is the default, but can be changed by 'enumStyle' config\n- name: ENUM_VALUE\n  enabled: true\n  configuration:\n    # Two options: SNAKE_CASE (default), PascalCase\n    enumStyle: SNAKE_CASE\n# Checks that class which extends any Exception class has Exception suffix\n- name: EXCEPTION_SUFFIX\n  enabled: true\n# Checks that file name has extension\n- name: FILE_NAME_INCORRECT\n  enabled: true\n# Checks that file name matches class name, if it is only one class in file\n- name: FILE_NAME_MATCH_CLASS\n  enabled: true\n# Checks that functions/methods which return boolean have special prefix like \"is/should/e.t.c\"\n- name: FUNCTION_BOOLEAN_PREFIX\n  enabled: true\n  configuration:\n    allowedPrefixes: \"\" # A list of functions that return boolean and are allowed to use. Input is in a form \"foo, bar\".\n# Checks that function/method name is in lowerCamelCase\n- name: FUNCTION_NAME_INCORRECT_CASE\n  enabled: true\n# Checks that typealias name is in PascalCase\n- name: TYPEALIAS_NAME_INCORRECT_CASE\n  enabled: true\n# Checks that generic name doesn't contain more than 1 letter (capital). It can be followed by numbers, example: T12, T\n- name: GENERIC_NAME\n  enabled: true\n# Identifier length should be in range [2,64] except names that used in industry like {i, j} and 'e' for catching exceptions\n- name: IDENTIFIER_LENGTH\n  enabled: true\n# Checks that the object matches PascalCase\n- name: OBJECT_NAME_INCORRECT\n  enabled: true\n# Checks that package name is in correct (lower) case\n- name: PACKAGE_NAME_INCORRECT_CASE\n  enabled: true\n# Checks that package name starts with the company's domain\n- name: PACKAGE_NAME_INCORRECT_PREFIX\n  enabled: false\n# Checks that package name does not have incorrect symbols like underscore or non-ASCII letters/digits\n- name: PACKAGE_NAME_INCORRECT_SYMBOLS\n  enabled: true\n# Checks that the path for a file matches with a package name\n- name: PACKAGE_NAME_INCORRECT_PATH\n  enabled: false\n# Checks that package name is in the file\n- name: PACKAGE_NAME_MISSING\n  enabled: true\n# Checks that variable does not have prefix (like mVariable or M_VARIABLE)\n- name: VARIABLE_HAS_PREFIX\n  enabled: true\n# Checks that variable does not contain one single letter, only exceptions are fixed names that used in industry like {i, j}\n- name: VARIABLE_NAME_INCORRECT\n  enabled: true\n# Checks that the name of variable is in lowerCamelCase and contains only ASCII letters\n- name: VARIABLE_NAME_INCORRECT_FORMAT\n  enabled: true\n# Checks that functions have kdoc\n- name: MISSING_KDOC_ON_FUNCTION\n  enabled: true\n# Checks that on file level internal or public class or function has missing KDoc\n- name: MISSING_KDOC_TOP_LEVEL\n  enabled: true\n# Checks that accessible internal elements (protected, public, internal) in a class are documented\n- name: MISSING_KDOC_CLASS_ELEMENTS\n  enabled: true\n# Checks that accessible method parameters are documented in KDoc\n- name: KDOC_WITHOUT_PARAM_TAG\n  enabled: true\n# Checks that accessible method explicit return type is documented in KDoc\n- name: KDOC_WITHOUT_RETURN_TAG\n  enabled: true\n# Checks that accessible method throw keyword is documented in KDoc\n- name: KDOC_WITHOUT_THROWS_TAG\n  enabled: true\n# Checks that KDoc is not empty\n- name: KDOC_EMPTY_KDOC\n  enabled: true\n# Checks that underscore is correctly used to split package naming\n- name: INCORRECT_PACKAGE_SEPARATOR\n  enabled: true\n# Checks that code block doesn't contain kdoc comments\n- name: COMMENTED_BY_KDOC\n  enabled: true\n# Checks that there is no @deprecated tag in kdoc\n- name: KDOC_NO_DEPRECATED_TAG\n  enabled: true\n# Checks that there is no empty content in kdoc tags\n- name: KDOC_NO_EMPTY_TAGS\n  enabled: true\n# Checks that there is only one space after kdoc tag\n- name: KDOC_WRONG_SPACES_AFTER_TAG\n  enabled: true\n# Checks tags order in kDoc. `@param`, `@return`, `@throws`\n- name: KDOC_WRONG_TAGS_ORDER\n  enabled: true\n# Checks that there is no newline of empty KDoc line (with leading asterisk) between `@param`, `@return`, `@throws` tags\n- name: KDOC_NO_NEWLINES_BETWEEN_BASIC_TAGS\n  enabled: true\n# Checks that block of tags @param, @return, @throws is separated from previous part of KDoc by exactly one empty line\n- name: KDOC_NEWLINES_BEFORE_BASIC_TAGS\n  enabled: true\n# Checks that special tags `@apiNote`, `@implNote`, `@implSpec` have exactly one empty line after\n- name: KDOC_NO_NEWLINE_AFTER_SPECIAL_TAGS\n  enabled: true\n# Checks that kdoc does not contain @author tag or date\n- name: KDOC_CONTAINS_DATE_OR_AUTHOR\n  enabled: true\n  configuration:\n    versionRegex: \\d+\\.\\d+\\.\\d+[-.\\w\\d]*\n# Checks that KDoc does not contain single line with words 'return', 'get' or 'set'\n- name: KDOC_TRIVIAL_KDOC_ON_FUNCTION\n  enabled: true\n# Checks that there is newline after header KDoc\n- name: HEADER_WRONG_FORMAT\n  enabled: true\n# Checks that file with zero or >1 classes has header KDoc\n- name: HEADER_MISSING_IN_NON_SINGLE_CLASS_FILE\n  enabled: true\n# Checks that copyright exists on top of file and is properly formatted (as a block comment)\n- name: HEADER_MISSING_OR_WRONG_COPYRIGHT\n  enabled: true\n  configuration:\n    isCopyrightMandatory: false\n    copyrightText: 'Copyright (c) Your Company Name Here. 2010-;@currYear;'\n# Checks that header kdoc is located before package directive\n- name: HEADER_NOT_BEFORE_PACKAGE\n  enabled: true\n# Checks that file does not contain lines > maxSize\n- name: FILE_IS_TOO_LONG\n  enabled: true\n  configuration:\n    # number of lines\n    maxSize: '2000'\n# Checks that file does not contain commented out code\n- name: COMMENTED_OUT_CODE\n  enabled: true\n# Checks that file does not contain only comments, imports and package directive\n- name: FILE_CONTAINS_ONLY_COMMENTS\n  enabled: true\n# Orders imports alphabetically\n- name: FILE_UNORDERED_IMPORTS\n  enabled: true\n  configuration:\n    # use logical imports grouping with sorting inside of a group\n    useRecommendedImportsOrder: true\n# Checks that general order of code parts is right\n- name: FILE_INCORRECT_BLOCKS_ORDER\n  enabled: true\n# Checks that there is exactly one line between code blocks\n- name: FILE_NO_BLANK_LINE_BETWEEN_BLOCKS\n  enabled: true\n# Checks that there is no wildcard imports. Exception: allowedWildcards\n- name: FILE_WILDCARD_IMPORTS\n  enabled: true\n  configuration:\n    allowedWildcards: \"\" # Allowed wildcards for imports (e.g. \"import com.saveourtool.diktat.*, import org.jetbrains.kotlin.*\")\n    useRecommendedImportsOrder: true\n# Checks unused imports\n- name: UNUSED_IMPORT\n  enabled: true\n  configuration:\n    deleteUnusedImport: true\n# Checks that braces are used in if, else, when, for, do, and while statements. Exception: single line ternary operator statement\n- name: NO_BRACES_IN_CONDITIONALS_AND_LOOPS\n  enabled: true\n# Checks that the declaration part of a class-like code structures (class/interface/etc.) is in the proper order\n- name: WRONG_ORDER_IN_CLASS_LIKE_STRUCTURES\n  enabled: true\n# Checks that properties with comments are separated by a blank line\n- name: BLANK_LINE_BETWEEN_PROPERTIES\n  enabled: true\n# Checks top level order\n- name: TOP_LEVEL_ORDER\n  enabled: true\n# Checks that non-empty code blocks with braces follow the K&R style (1TBS or OTBS style)\n- name: BRACES_BLOCK_STRUCTURE_ERROR\n  enabled: true\n  configuration:\n    openBraceNewline: 'True'\n    closeBraceNewline: 'True'\n# Checks that indentation is correct\n- name: WRONG_INDENTATION\n  enabled: true\n  configuration:\n    # Is newline at the end of a file needed\n    newlineAtEnd: true\n    # If true: in parameter list when parameters are split by newline they are indented with two indentations instead of one\n    extendedIndentOfParameters: false\n    # If true: if first parameter in parameter list is on the same line as opening parenthesis, then other parameters can be aligned with it\n    alignedParameters: true\n    # If true, expression bodies which begin on a separate line are indented\n    # using a continuation indent. The default is false.\n    #\n    # This flag is called CONTINUATION_INDENT_FOR_EXPRESSION_BODIES in IDEA and\n    # ij_kotlin_continuation_indent_for_expression_bodies in .editorconfig.\n    extendedIndentForExpressionBodies: false\n    # If true: if expression is split by newline after operator like +/-/`*`, then the next line is indented with two indentations instead of one\n    extendedIndentAfterOperators: true\n    # If true: when dot qualified expression starts on a new line, this line will be indented with two indentations instead of one\n    extendedIndentBeforeDot: false\n    # The indentation size for each file\n    indentationSize: 4\n# Checks that there is no empty blocks in a file.\n# If allowEmptyBlocks is true, checks that it follows correct style (have a newline)\n- name: EMPTY_BLOCK_STRUCTURE_ERROR\n  enabled: true\n  configuration:\n    # Whether a newline after `{` is required in an empty block\n    styleEmptyBlockWithNewline: 'True'\n    allowEmptyBlocks: 'False'\n# Checks that there is no more than one statement per line\n- name: MORE_THAN_ONE_STATEMENT_PER_LINE\n  enabled: true\n# Checks that the line length is < lineLength parameter\n- name: LONG_LINE\n  enabled: true\n  configuration:\n    lineLength: '120'\n# Checks that semicolons are not used at the end of a line\n- name: REDUNDANT_SEMICOLON\n  enabled: true\n# Checks that line breaks follow code style guide: rule 3.6\n- name: WRONG_NEWLINES\n  enabled: true\n  configuration:\n    # If the number of parameters on one line is more than this threshold, all parameters will be placed on separate lines.\n    maxParametersInOneLine: 2\n    # 3 by default.\n    maxCallsInOneLine: 3\n# Checks trailing comma\n- name: TRAILING_COMMA\n  enabled: true\n  configuration:\n    # VALUE_ARGUMENT\n    valueArgument: false\n    # VALUE_PARAMETER\n    valueParameter: false\n    # REFERENCE_EXPRESSION\n    indices: false\n    # WHEN_CONDITION_WITH_EXPRESSION\n    whenConditions: false\n    # STRING_TEMPLATE\n    collectionLiteral: false\n    # TYPE_PROJECTION\n    typeArgument: false\n    # TYPE_PARAMETER\n    typeParameter: false\n    # DESTRUCTURING_DECLARATION_ENTRY\n    destructuringDeclaration: false\n# Checks that there are not too many consecutive spaces in line\n- name: TOO_MANY_CONSECUTIVE_SPACES\n  enabled: true\n  configuration:\n    # Maximum allowed number of consecutive spaces (not counting indentation)\n    maxSpaces: '1'\n    # Whether formatting for enums should be kept without checking\n    saveInitialFormattingForEnums: false\n# Inspection that checks if a long dot qualified expression is used in condition or as an argument\n- name: COMPLEX_EXPRESSION\n  enabled: true\n# Checks that blank lines are used correctly.\n# For example: triggers when there are too many blank lines between function declaration\n- name: TOO_MANY_BLANK_LINES\n  enabled: true\n# Checks that usage of horizontal spaces doesn't violate code style guide\n- name: WRONG_WHITESPACE\n  enabled: true\n# Checks that backticks (``) are not used in the identifier name, except the case when it is test method (marked with @Test annotation)\n- name: BACKTICKS_PROHIBITED\n  enabled: true\n# Checks that a single line concatenation of strings is not used\n- name: STRING_CONCATENATION\n  enabled: true\n# Checks that each when statement have else in the end\n- name: WHEN_WITHOUT_ELSE\n  enabled: true\n# Checks that annotation is on a single line\n- name: ANNOTATION_NEW_LINE\n  enabled: true\n# Checks that method annotated with `Preview` annotation is private and has Preview suffix\n- name: PREVIEW_ANNOTATION\n  enabled: true\n# Checks that enum structure is correct: enum entries should be separated by comma and line break and last entry should have semicolon in the end.\n- name: ENUMS_SEPARATED\n  enabled: true\n# Checks that value on integer or float constant is not too big\n- name: LONG_NUMERICAL_VALUES_SEPARATED\n  enabled: true\n  configuration:\n    # Maximum number of digits which are not split\n    maxNumberLength: '5'\n    # Maximum number of digits between separators\n    maxBlockLength: '3'\n# Checks magic number\n- name: MAGIC_NUMBER\n  enabled: true\n  configuration:\n    # Ignore numbers from test\n    ignoreTest: \"true\"\n    # Ignore numbers\n    ignoreNumbers: \"-1, 1, 0, 2, 0U, 1U, 2U, -1L, 0L, 1L, 2L, 0UL, 1UL, 2UL\"\n    # Is ignore override hashCode function\n    ignoreHashCodeFunction: \"true\"\n    # Is ignore property\n    ignorePropertyDeclaration: \"false\"\n    # Is ignore local variable\n    ignoreLocalVariableDeclaration: \"false\"\n    # Is ignore value parameter\n    ignoreValueParameter: \"true\"\n    # Is ignore constant\n    ignoreConstantDeclaration: \"true\"\n    # Is ignore property in companion object\n    ignoreCompanionObjectPropertyDeclaration: \"true\"\n    # Is ignore numbers in enum\n    ignoreEnums: \"false\"\n    # Is ignore number in ranges\n    ignoreRanges: \"false\"\n    # Is ignore number in extension function\n    ignoreExtensionFunctions: \"false\"\n    # Is ignore number in pairs created using to\n    ignorePairsCreatedUsingTo: \"false\"\n# Checks that order of enum values or constant property inside companion is correct\n- name: WRONG_DECLARATIONS_ORDER\n  enabled: true\n  configuration:\n    # Whether enum members should be sorted alphabetically\n    sortEnum: true\n    # Whether class properties should be sorted alphabetically\n    sortProperty: true\n# Checks that multiple modifiers sequence is in the correct order\n- name: WRONG_MULTIPLE_MODIFIERS_ORDER\n  enabled: true\n# Checks that identifier has appropriate name (See table of rule 1.2 part 6)\n- name: CONFUSING_IDENTIFIER_NAMING\n  enabled: true\n# Checks year in the copyright\n- name: WRONG_COPYRIGHT_YEAR\n  enabled: true\n# Inspection that checks if local variables are declared close to the first usage site\n- name: LOCAL_VARIABLE_EARLY_DECLARATION\n  enabled: true\n# Try to avoid initialize val by null (e.g. val a: Int? = null -> val a: Int = 0)\n- name: NULLABLE_PROPERTY_TYPE\n  enabled: true\n# Inspection that checks if there is a blank line before kDoc and none after\n- name: WRONG_NEWLINES_AROUND_KDOC\n  enabled: true\n# Inspection that checks if there is no blank lines before first comment\n- name: FIRST_COMMENT_NO_BLANK_LINE\n  enabled: true\n# Inspection that checks if there are blank lines between code and comment and between code start token and comment's text\n- name: COMMENT_WHITE_SPACE\n  enabled: true\n  configuration:\n    maxSpacesBeforeComment: 2\n    maxSpacesInComment: 1\n# Inspection that checks if all comment's are inside if-else code blocks. Exception is general if comment\n- name: IF_ELSE_COMMENTS\n  enabled: true\n# Type aliases provide alternative names for existing types when type's reference text is longer 25 chars\n- name: TYPE_ALIAS\n  enabled: true\n  configuration:\n    typeReferenceLength: '25' # max length of type reference\n# Checks if casting can be omitted\n- name: SMART_CAST_NEEDED\n  enabled: true\n# Checks that variables of generic types have explicit type declaration\n- name: GENERIC_VARIABLE_WRONG_DECLARATION\n  enabled: true\n# Inspection that checks if string template has redundant curly braces\n- name: STRING_TEMPLATE_CURLY_BRACES\n  enabled: true\n# Variables with `val` modifier - are immutable (read-only). Usage of such variables instead of `var` variables increases\n# robustness and readability of code, because `var` variables can be reassigned several times in the business logic.\n# This rule prohibits usage of `var`s as local variables - the only exception is accumulators and counters\n- name: SAY_NO_TO_VAR\n  enabled: true\n# Inspection that checks if string template has redundant quotes\n- name: STRING_TEMPLATE_QUOTES\n  enabled: true\n# Check if there are redundant nested if-statements, which could be collapsed into a single one by concatenating their conditions\n- name: COLLAPSE_IF_STATEMENTS\n  enabled: true\n  configuration:\n    startCollapseFromNestedLevel: 2\n# Checks that floating-point values are not used in arithmetic expressions\n- name: FLOAT_IN_ACCURATE_CALCULATIONS\n  enabled: true\n# Checks that function length isn't too long\n- name: TOO_LONG_FUNCTION\n  enabled: true\n  configuration:\n    maxFunctionLength: '30' # max length of function\n    isIncludeHeader: 'false' # count function's header\n# Warns if there are nested functions\n- name: AVOID_NESTED_FUNCTIONS\n  enabled: true\n# Checks that lambda inside function parameters is in the end\n- name: LAMBDA_IS_NOT_LAST_PARAMETER\n  enabled: true\n# Checks that function doesn't contains too many parameters\n- name: TOO_MANY_PARAMETERS\n  enabled: true\n  configuration:\n    maxParameterListSize: '5' # max parameters size\n# Checks that function doesn't have too many nested blocks\n- name: NESTED_BLOCK\n  enabled: true\n  configuration:\n    maxNestedBlockQuantity: '4'\n# Checks that function use default values, instead overloading\n- name: WRONG_OVERLOADING_FUNCTION_ARGUMENTS\n  enabled: true\n# Checks that using runBlocking inside async block code\n- name: RUN_BLOCKING_INSIDE_ASYNC\n  enabled: true\n# Checks that property in constructor doesn't contain comment\n- name: KDOC_NO_CONSTRUCTOR_PROPERTY\n  enabled: true\n  configuration:\n    isParamTagsForParameters: true # create param tags for parameters without val or var\n    isParamTagsForPrivateProperties: true # create param tags for private properties\n    isParamTagsForGenericTypes: true # create param tags for generic types\n# Checks that the long lambda has parameters\n- name: TOO_MANY_LINES_IN_LAMBDA\n  enabled: true\n  configuration:\n    maxLambdaLength: 10 # max length of lambda without parameters\n# Checks that using unnecessary, custom label\n- name: CUSTOM_LABEL\n  enabled: true\n# Check that lambda with inner lambda doesn't use implicit parameter\n- name: PARAMETER_NAME_IN_OUTER_LAMBDA\n  enabled: true\n# Checks that property in KDoc present in class\n- name: KDOC_EXTRA_PROPERTY\n  enabled: true\n# There's a property in KDoc which is already present\n- name: KDOC_DUPLICATE_PROPERTY\n  enabled: true\n# Checks that KDoc in constructor has property tag but with comment inside constructor\n- name: KDOC_NO_CONSTRUCTOR_PROPERTY_WITH_COMMENT\n  enabled: true\n# if a class has single constructor, it should be converted to a primary constructor\n- name: SINGLE_CONSTRUCTOR_SHOULD_BE_PRIMARY\n  enabled: true\n# Checks if class can be made as data class\n- name: USE_DATA_CLASS\n  enabled: true\n# Checks that never use the name of a variable in the custom getter or setter\n- name: WRONG_NAME_OF_VARIABLE_INSIDE_ACCESSOR\n  enabled: true\n# Checks that classes have only one init block\n- name: MULTIPLE_INIT_BLOCKS\n  enabled: true\n# Checks that there are abstract functions in abstract class\n- name: CLASS_SHOULD_NOT_BE_ABSTRACT\n  enabled: true\n# Checks if there are any trivial getters or setters\n- name: TRIVIAL_ACCESSORS_ARE_NOT_RECOMMENDED\n  enabled: true\n# Checks that no custom getters and setters are used for properties. It is a more wide rule than TRIVIAL_ACCESSORS_ARE_NOT_RECOMMENDED\n# Kotlin compiler automatically generates `get` and `set` methods for properties and also lets the possibility to override it.\n# But in all cases it is very confusing when `get` and `set` are overridden for a developer who uses this particular class.\n# Developer expects to get the value of the property, but receives some unknown value and some extra side effect hidden by the custom getter/setter.\n# Use extra functions for it instead.\n- name: CUSTOM_GETTERS_SETTERS\n  enabled: true\n# Checks if null-check was used explicitly (for example: if (a == null))\n# Try to avoid explicit null checks (explicit comparison with `null`)\n# Kotlin is declared as [Null-safe](https://kotlinlang.org/docs/reference/null-safety.html) language.\n# But Kotlin architects wanted Kotlin to be fully compatible with Java, that's why `null` keyword was also introduced in Kotlin.\n# There are several code-structures that can be used in Kotlin to avoid null-checks. For example: `?:`,  `.let {}`, `.also {}`, e.t.c\n- name: AVOID_NULL_CHECKS\n  enabled: true\n# Checks if class instantiation can be wrapped in `apply` for better readability\n- name: COMPACT_OBJECT_INITIALIZATION\n  enabled: true\n# Checks explicit supertype qualification\n- name: USELESS_SUPERTYPE\n  enabled: true\n# Checks if extension function with the same signature don't have related classes\n- name: EXTENSION_FUNCTION_SAME_SIGNATURE\n  enabled: true\n# Checks if there is empty primary constructor\n- name: EMPTY_PRIMARY_CONSTRUCTOR\n  enabled: true\n# In case of not using field keyword in property accessors,\n# there should be explicit backing property with the name of real property\n# Example: val table get() {if (_table == null) ...} -> table should have _table\n- name: NO_CORRESPONDING_PROPERTY\n  enabled: true\n# Checks if there is class/object that can be replace with extension function\n- name: AVOID_USING_UTILITY_CLASS\n  enabled: true\n# If there is stateless class it is preferred to use object\n- name: OBJECT_IS_PREFERRED\n  enabled: true\n# If there exists negated version of function you should prefer it instead of !functionCall\n- name: INVERSE_FUNCTION_PREFERRED\n  enabled: true\n# Checks if class can be converted to inline class\n- name: INLINE_CLASS_CAN_BE_USED\n  enabled: true\n# If file contains class, then it can't contain extension functions for the same class\n- name: EXTENSION_FUNCTION_WITH_CLASS\n  enabled: true\n# Check if kts script contains other functions except run code\n- name: RUN_IN_SCRIPT\n  enabled: true\n# Check if boolean expression can be simplified\n- name: COMPLEX_BOOLEAN_EXPRESSION\n  enabled: true\n# Check if range can replace with until or `rangeTo` function with range\n- name: CONVENTIONAL_RANGE\n  enabled: true\n  configuration:\n    isRangeToIgnore: false\n# Check if there is a call of print()\\println() or console.log(). Assumption that it's a debug print\n- name: DEBUG_PRINT\n  enabled: true\n# Check that typealias name is in PascalCase\n- name: TYPEALIAS_NAME_INCORRECT_CASE\n  enabled: true\n# Should change property length - 1 to property lastIndex\n- name: USE_LAST_INDEX\n  enabled: true\n# Only properties from the primary constructor should be documented in a @property tag in class KDoc\n- name: KDOC_NO_CLASS_BODY_PROPERTIES_IN_HEADER\n  enabled: true\n"
  },
  {
    "path": "examples/gradle-kotlin-dsl-multiproject/frontend/build.gradle.kts",
    "content": "plugins {\n    kotlin(\"jvm\")\n}\n"
  },
  {
    "path": "examples/gradle-kotlin-dsl-multiproject/frontend/src/main/kotlin/AnotherTest.kt",
    "content": "package whate.ver\n\nfun String.createPluginConfig() {\n    val pluginConfig = TomlDecoder.decode<T>(\n        serializer(),\n        fakeFileNode,\n        DecoderConf()\n    )\n    pluginConfig.configLocation = this.toPath()\n    pluginConfig.prop1 = property1\n    // comment1\n    pluginConfig.configLocation2 = this.toPath()\n    // comment2\n    pluginConfig.prop2 = property2\n}\n"
  },
  {
    "path": "examples/gradle-kotlin-dsl-multiproject/settings.gradle.kts",
    "content": "include(\":backend\")\ninclude(\":frontend\")\n"
  },
  {
    "path": "examples/maven/diktat-analysis.yml",
    "content": "# Common configuration\n- name: DIKTAT_COMMON\n  configuration:\n    # put your package name here - it will be autofixed and checked\n    domainName: your.name.here\n    testDirs: test\n    # expected values:  disabledChapters: \"Naming, Comments, General, Variables, Functions, Classes\"\n    # or: \"1, 2, 3, 4, 5, 6\"\n    disabledChapters: \"\"\n    kotlinVersion: 2.1\n    srcDirectories: \"main\"\n# Checks that the Class/Enum/Interface name matches Pascal case\n- name: CLASS_NAME_INCORRECT\n  enabled: true\n  # all code blocks with MyAnnotation will be ignored and not checked\n  ignoreAnnotated: [ MyAnnotation ]\n# Checks that CONSTANT (treated as const val from companion object or class level) is in non UPPER_SNAKE_CASE\n- name: CONSTANT_UPPERCASE\n  enabled: true\n# Checks that enum value is in upper SNAKE_CASE or in PascalCase depending on the config. UPPER_SNAKE_CASE is the default, but can be changed by 'enumStyle' config\n- name: ENUM_VALUE\n  enabled: true\n  configuration:\n    # Two options: SNAKE_CASE (default), PascalCase\n    enumStyle: SNAKE_CASE\n# Checks that class which extends any Exception class has Exception suffix\n- name: EXCEPTION_SUFFIX\n  enabled: true\n# Checks that file name has extension\n- name: FILE_NAME_INCORRECT\n  enabled: true\n# Checks that file name matches class name, if it is only one class in file\n- name: FILE_NAME_MATCH_CLASS\n  enabled: true\n# Checks that functions/methods which return boolean have special prefix like \"is/should/e.t.c\"\n- name: FUNCTION_BOOLEAN_PREFIX\n  enabled: true\n  configuration:\n    allowedPrefixes: \"\" # A list of functions that return boolean and are allowed to use. Input is in a form \"foo, bar\".\n# Checks that function/method name is in lowerCamelCase\n- name: FUNCTION_NAME_INCORRECT_CASE\n  enabled: true\n# Checks that typealias name is in PascalCase\n- name: TYPEALIAS_NAME_INCORRECT_CASE\n  enabled: true\n# Checks that generic name doesn't contain more than 1 letter (capital). It can be followed by numbers, example: T12, T\n- name: GENERIC_NAME\n  enabled: true\n# Identifier length should be in range [2,64] except names that used in industry like {i, j} and 'e' for catching exceptions\n- name: IDENTIFIER_LENGTH\n  enabled: true\n# Checks that the object matches PascalCase\n- name: OBJECT_NAME_INCORRECT\n  enabled: true\n# Checks that package name is in correct (lower) case\n- name: PACKAGE_NAME_INCORRECT_CASE\n  enabled: true\n# Checks that package name starts with the company's domain\n- name: PACKAGE_NAME_INCORRECT_PREFIX\n  enabled: false\n# Checks that package name does not have incorrect symbols like underscore or non-ASCII letters/digits\n- name: PACKAGE_NAME_INCORRECT_SYMBOLS\n  enabled: true\n# Checks that the path for a file matches with a package name\n- name: PACKAGE_NAME_INCORRECT_PATH\n  enabled: false\n# Checks that package name is in the file\n- name: PACKAGE_NAME_MISSING\n  enabled: true\n# Checks that variable does not have prefix (like mVariable or M_VARIABLE)\n- name: VARIABLE_HAS_PREFIX\n  enabled: true\n# Checks that variable does not contain one single letter, only exceptions are fixed names that used in industry like {i, j}\n- name: VARIABLE_NAME_INCORRECT\n  enabled: true\n# Checks that the name of variable is in lowerCamelCase and contains only ASCII letters\n- name: VARIABLE_NAME_INCORRECT_FORMAT\n  enabled: true\n# Checks that functions have kdoc\n- name: MISSING_KDOC_ON_FUNCTION\n  enabled: true\n# Checks that on file level internal or public class or function has missing KDoc\n- name: MISSING_KDOC_TOP_LEVEL\n  enabled: true\n# Checks that accessible internal elements (protected, public, internal) in a class are documented\n- name: MISSING_KDOC_CLASS_ELEMENTS\n  enabled: true\n# Checks that accessible method parameters are documented in KDoc\n- name: KDOC_WITHOUT_PARAM_TAG\n  enabled: true\n# Checks that accessible method explicit return type is documented in KDoc\n- name: KDOC_WITHOUT_RETURN_TAG\n  enabled: true\n# Checks that accessible method throw keyword is documented in KDoc\n- name: KDOC_WITHOUT_THROWS_TAG\n  enabled: true\n# Checks that KDoc is not empty\n- name: KDOC_EMPTY_KDOC\n  enabled: true\n# Checks that underscore is correctly used to split package naming\n- name: INCORRECT_PACKAGE_SEPARATOR\n  enabled: true\n# Checks that code block doesn't contain kdoc comments\n- name: COMMENTED_BY_KDOC\n  enabled: true\n# Checks that there is no @deprecated tag in kdoc\n- name: KDOC_NO_DEPRECATED_TAG\n  enabled: true\n# Checks that there is no empty content in kdoc tags\n- name: KDOC_NO_EMPTY_TAGS\n  enabled: true\n# Checks that there is only one space after kdoc tag\n- name: KDOC_WRONG_SPACES_AFTER_TAG\n  enabled: true\n# Checks tags order in kDoc. `@param`, `@return`, `@throws`\n- name: KDOC_WRONG_TAGS_ORDER\n  enabled: true\n# Checks that there is no newline of empty KDoc line (with leading asterisk) between `@param`, `@return`, `@throws` tags\n- name: KDOC_NO_NEWLINES_BETWEEN_BASIC_TAGS\n  enabled: true\n# Checks that block of tags @param, @return, @throws is separated from previous part of KDoc by exactly one empty line\n- name: KDOC_NEWLINES_BEFORE_BASIC_TAGS\n  enabled: true\n# Checks that special tags `@apiNote`, `@implNote`, `@implSpec` have exactly one empty line after\n- name: KDOC_NO_NEWLINE_AFTER_SPECIAL_TAGS\n  enabled: true\n# Checks that kdoc does not contain @author tag or date\n- name: KDOC_CONTAINS_DATE_OR_AUTHOR\n  enabled: true\n  configuration:\n    versionRegex: \\d+\\.\\d+\\.\\d+[-.\\w\\d]*\n# Checks that KDoc does not contain single line with words 'return', 'get' or 'set'\n- name: KDOC_TRIVIAL_KDOC_ON_FUNCTION\n  enabled: true\n# Checks that there is newline after header KDoc\n- name: HEADER_WRONG_FORMAT\n  enabled: true\n# Checks that file with zero or >1 classes has header KDoc\n- name: HEADER_MISSING_IN_NON_SINGLE_CLASS_FILE\n  enabled: true\n# Checks that copyright exists on top of file and is properly formatted (as a block comment)\n- name: HEADER_MISSING_OR_WRONG_COPYRIGHT\n  enabled: true\n  configuration:\n    isCopyrightMandatory: false\n    copyrightText: 'Copyright (c) Your Company Name Here. 2010-;@currYear;'\n# Checks that header kdoc is located before package directive\n- name: HEADER_NOT_BEFORE_PACKAGE\n  enabled: true\n# Checks that file does not contain lines > maxSize\n- name: FILE_IS_TOO_LONG\n  enabled: true\n  configuration:\n    # number of lines\n    maxSize: '2000'\n# Checks that file does not contain commented out code\n- name: COMMENTED_OUT_CODE\n  enabled: true\n# Checks that file does not contain only comments, imports and package directive\n- name: FILE_CONTAINS_ONLY_COMMENTS\n  enabled: true\n# Orders imports alphabetically\n- name: FILE_UNORDERED_IMPORTS\n  enabled: true\n  configuration:\n    # use logical imports grouping with sorting inside of a group\n    useRecommendedImportsOrder: true\n# Checks that general order of code parts is right\n- name: FILE_INCORRECT_BLOCKS_ORDER\n  enabled: true\n# Checks that there is exactly one line between code blocks\n- name: FILE_NO_BLANK_LINE_BETWEEN_BLOCKS\n  enabled: true\n# Checks that there is no wildcard imports. Exception: allowedWildcards\n- name: FILE_WILDCARD_IMPORTS\n  enabled: true\n  configuration:\n    allowedWildcards: \"\" # Allowed wildcards for imports (e.g. \"import com.saveourtool.diktat.*, import org.jetbrains.kotlin.*\")\n    useRecommendedImportsOrder: true\n# Checks unused imports\n- name: UNUSED_IMPORT\n  enabled: true\n  configuration:\n    deleteUnusedImport: true\n# Checks that braces are used in if, else, when, for, do, and while statements. Exception: single line ternary operator statement\n- name: NO_BRACES_IN_CONDITIONALS_AND_LOOPS\n  enabled: true\n# Checks that the declaration part of a class-like code structures (class/interface/etc.) is in the proper order\n- name: WRONG_ORDER_IN_CLASS_LIKE_STRUCTURES\n  enabled: true\n# Checks that properties with comments are separated by a blank line\n- name: BLANK_LINE_BETWEEN_PROPERTIES\n  enabled: true\n# Checks top level order\n- name: TOP_LEVEL_ORDER\n  enabled: true\n# Checks that non-empty code blocks with braces follow the K&R style (1TBS or OTBS style)\n- name: BRACES_BLOCK_STRUCTURE_ERROR\n  enabled: true\n  configuration:\n    openBraceNewline: 'True'\n    closeBraceNewline: 'True'\n# Checks that indentation is correct\n- name: WRONG_INDENTATION\n  enabled: true\n  configuration:\n    # Is newline at the end of a file needed\n    newlineAtEnd: true\n    # If true: in parameter list when parameters are split by newline they are indented with two indentations instead of one\n    extendedIndentOfParameters: false\n    # If true: if first parameter in parameter list is on the same line as opening parenthesis, then other parameters can be aligned with it\n    alignedParameters: true\n    # If true, expression bodies which begin on a separate line are indented\n    # using a continuation indent. The default is false.\n    #\n    # This flag is called CONTINUATION_INDENT_FOR_EXPRESSION_BODIES in IDEA and\n    # ij_kotlin_continuation_indent_for_expression_bodies in .editorconfig.\n    extendedIndentForExpressionBodies: false\n    # If true: if expression is split by newline after operator like +/-/`*`, then the next line is indented with two indentations instead of one\n    extendedIndentAfterOperators: true\n    # If true: when dot qualified expression starts on a new line, this line will be indented with two indentations instead of one\n    extendedIndentBeforeDot: false\n    # The indentation size for each file\n    indentationSize: 4\n# Checks that there is no empty blocks in a file.\n# If allowEmptyBlocks is true, checks that it follows correct style (have a newline)\n- name: EMPTY_BLOCK_STRUCTURE_ERROR\n  enabled: true\n  configuration:\n    # Whether a newline after `{` is required in an empty block\n    styleEmptyBlockWithNewline: 'True'\n    allowEmptyBlocks: 'False'\n# Checks that there is no more than one statement per line\n- name: MORE_THAN_ONE_STATEMENT_PER_LINE\n  enabled: true\n# Checks that the line length is < lineLength parameter\n- name: LONG_LINE\n  enabled: true\n  configuration:\n    lineLength: '120'\n# Checks that semicolons are not used at the end of a line\n- name: REDUNDANT_SEMICOLON\n  enabled: true\n# Checks that line breaks follow code style guide: rule 3.6\n- name: WRONG_NEWLINES\n  enabled: true\n  configuration:\n    # If the number of parameters on one line is more than this threshold, all parameters will be placed on separate lines.\n    maxParametersInOneLine: 2\n    # 3 by default.\n    maxCallsInOneLine: 3\n# Checks trailing comma\n- name: TRAILING_COMMA\n  enabled: true\n  configuration:\n    # VALUE_ARGUMENT\n    valueArgument: false\n    # VALUE_PARAMETER\n    valueParameter: false\n    # REFERENCE_EXPRESSION\n    indices: false\n    # WHEN_CONDITION_WITH_EXPRESSION\n    whenConditions: false\n    # STRING_TEMPLATE\n    collectionLiteral: false\n    # TYPE_PROJECTION\n    typeArgument: false\n    # TYPE_PARAMETER\n    typeParameter: false\n    # DESTRUCTURING_DECLARATION_ENTRY\n    destructuringDeclaration: false\n# Checks that there are not too many consecutive spaces in line\n- name: TOO_MANY_CONSECUTIVE_SPACES\n  enabled: true\n  configuration:\n    # Maximum allowed number of consecutive spaces (not counting indentation)\n    maxSpaces: '1'\n    # Whether formatting for enums should be kept without checking\n    saveInitialFormattingForEnums: false\n# Inspection that checks if a long dot qualified expression is used in condition or as an argument\n- name: COMPLEX_EXPRESSION\n  enabled: true\n# Checks that blank lines are used correctly.\n# For example: triggers when there are too many blank lines between function declaration\n- name: TOO_MANY_BLANK_LINES\n  enabled: true\n# Checks that usage of horizontal spaces doesn't violate code style guide\n- name: WRONG_WHITESPACE\n  enabled: true\n# Checks that backticks (``) are not used in the identifier name, except the case when it is test method (marked with @Test annotation)\n- name: BACKTICKS_PROHIBITED\n  enabled: true\n# Checks that a single line concatenation of strings is not used\n- name: STRING_CONCATENATION\n  enabled: true\n# Checks that each when statement have else in the end\n- name: WHEN_WITHOUT_ELSE\n  enabled: true\n# Checks that annotation is on a single line\n- name: ANNOTATION_NEW_LINE\n  enabled: true\n# Checks that method annotated with `Preview` annotation is private and has Preview suffix\n- name: PREVIEW_ANNOTATION\n  enabled: true\n# Checks that enum structure is correct: enum entries should be separated by comma and line break and last entry should have semicolon in the end.\n- name: ENUMS_SEPARATED\n  enabled: true\n# Checks that value on integer or float constant is not too big\n- name: LONG_NUMERICAL_VALUES_SEPARATED\n  enabled: true\n  configuration:\n    # Maximum number of digits which are not split\n    maxNumberLength: '5'\n    # Maximum number of digits between separators\n    maxBlockLength: '3'\n# Checks magic number\n- name: MAGIC_NUMBER\n  enabled: true\n  configuration:\n    # Ignore numbers from test\n    ignoreTest: \"true\"\n    # Ignore numbers\n    ignoreNumbers: \"-1, 1, 0, 2, 0U, 1U, 2U, -1L, 0L, 1L, 2L, 0UL, 1UL, 2UL\"\n    # Is ignore override hashCode function\n    ignoreHashCodeFunction: \"true\"\n    # Is ignore property\n    ignorePropertyDeclaration: \"false\"\n    # Is ignore local variable\n    ignoreLocalVariableDeclaration: \"false\"\n    # Is ignore value parameter\n    ignoreValueParameter: \"true\"\n    # Is ignore constant\n    ignoreConstantDeclaration: \"true\"\n    # Is ignore property in companion object\n    ignoreCompanionObjectPropertyDeclaration: \"true\"\n    # Is ignore numbers in enum\n    ignoreEnums: \"false\"\n    # Is ignore number in ranges\n    ignoreRanges: \"false\"\n    # Is ignore number in extension function\n    ignoreExtensionFunctions: \"false\"\n    # Is ignore number in pairs created using to\n    ignorePairsCreatedUsingTo: \"false\"\n# Checks that order of enum values or constant property inside companion is correct\n- name: WRONG_DECLARATIONS_ORDER\n  enabled: true\n  configuration:\n    # Whether enum members should be sorted alphabetically\n    sortEnum: true\n    # Whether class properties should be sorted alphabetically\n    sortProperty: true\n# Checks that multiple modifiers sequence is in the correct order\n- name: WRONG_MULTIPLE_MODIFIERS_ORDER\n  enabled: true\n# Checks that identifier has appropriate name (See table of rule 1.2 part 6)\n- name: CONFUSING_IDENTIFIER_NAMING\n  enabled: true\n# Checks year in the copyright\n- name: WRONG_COPYRIGHT_YEAR\n  enabled: true\n# Inspection that checks if local variables are declared close to the first usage site\n- name: LOCAL_VARIABLE_EARLY_DECLARATION\n  enabled: true\n# Try to avoid initialize val by null (e.g. val a: Int? = null -> val a: Int = 0)\n- name: NULLABLE_PROPERTY_TYPE\n  enabled: true\n# Inspection that checks if there is a blank line before kDoc and none after\n- name: WRONG_NEWLINES_AROUND_KDOC\n  enabled: true\n# Inspection that checks if there is no blank lines before first comment\n- name: FIRST_COMMENT_NO_BLANK_LINE\n  enabled: true\n# Inspection that checks if there are blank lines between code and comment and between code start token and comment's text\n- name: COMMENT_WHITE_SPACE\n  enabled: true\n  configuration:\n    maxSpacesBeforeComment: 2\n    maxSpacesInComment: 1\n# Inspection that checks if all comment's are inside if-else code blocks. Exception is general if comment\n- name: IF_ELSE_COMMENTS\n  enabled: true\n# Type aliases provide alternative names for existing types when type's reference text is longer 25 chars\n- name: TYPE_ALIAS\n  enabled: true\n  configuration:\n    typeReferenceLength: '25' # max length of type reference\n# Checks if casting can be omitted\n- name: SMART_CAST_NEEDED\n  enabled: true\n# Checks that variables of generic types have explicit type declaration\n- name: GENERIC_VARIABLE_WRONG_DECLARATION\n  enabled: true\n# Inspection that checks if string template has redundant curly braces\n- name: STRING_TEMPLATE_CURLY_BRACES\n  enabled: true\n# Variables with `val` modifier - are immutable (read-only). Usage of such variables instead of `var` variables increases\n# robustness and readability of code, because `var` variables can be reassigned several times in the business logic.\n# This rule prohibits usage of `var`s as local variables - the only exception is accumulators and counters\n- name: SAY_NO_TO_VAR\n  enabled: true\n# Inspection that checks if string template has redundant quotes\n- name: STRING_TEMPLATE_QUOTES\n  enabled: true\n# Check if there are redundant nested if-statements, which could be collapsed into a single one by concatenating their conditions\n- name: COLLAPSE_IF_STATEMENTS\n  enabled: true\n  configuration:\n    startCollapseFromNestedLevel: 2\n# Checks that floating-point values are not used in arithmetic expressions\n- name: FLOAT_IN_ACCURATE_CALCULATIONS\n  enabled: true\n# Checks that function length isn't too long\n- name: TOO_LONG_FUNCTION\n  enabled: true\n  configuration:\n    maxFunctionLength: '30' # max length of function\n    isIncludeHeader: 'false' # count function's header\n# Warns if there are nested functions\n- name: AVOID_NESTED_FUNCTIONS\n  enabled: true\n# Checks that lambda inside function parameters is in the end\n- name: LAMBDA_IS_NOT_LAST_PARAMETER\n  enabled: true\n# Checks that function doesn't contains too many parameters\n- name: TOO_MANY_PARAMETERS\n  enabled: true\n  configuration:\n    maxParameterListSize: '5' # max parameters size\n# Checks that function doesn't have too many nested blocks\n- name: NESTED_BLOCK\n  enabled: true\n  configuration:\n    maxNestedBlockQuantity: '4'\n# Checks that function use default values, instead overloading\n- name: WRONG_OVERLOADING_FUNCTION_ARGUMENTS\n  enabled: true\n# Checks that using runBlocking inside async block code\n- name: RUN_BLOCKING_INSIDE_ASYNC\n  enabled: true\n# Checks that property in constructor doesn't contain comment\n- name: KDOC_NO_CONSTRUCTOR_PROPERTY\n  enabled: true\n  configuration:\n    isParamTagsForParameters: true # create param tags for parameters without val or var\n    isParamTagsForPrivateProperties: true # create param tags for private properties\n    isParamTagsForGenericTypes: true # create param tags for generic types\n# Checks that the long lambda has parameters\n- name: TOO_MANY_LINES_IN_LAMBDA\n  enabled: true\n  configuration:\n    maxLambdaLength: 10 # max length of lambda without parameters\n# Checks that using unnecessary, custom label\n- name: CUSTOM_LABEL\n  enabled: true\n# Check that lambda with inner lambda doesn't use implicit parameter\n- name: PARAMETER_NAME_IN_OUTER_LAMBDA\n  enabled: true\n# Checks that property in KDoc present in class\n- name: KDOC_EXTRA_PROPERTY\n  enabled: true\n# There's a property in KDoc which is already present\n- name: KDOC_DUPLICATE_PROPERTY\n  enabled: true\n# Checks that KDoc in constructor has property tag but with comment inside constructor\n- name: KDOC_NO_CONSTRUCTOR_PROPERTY_WITH_COMMENT\n  enabled: true\n# if a class has single constructor, it should be converted to a primary constructor\n- name: SINGLE_CONSTRUCTOR_SHOULD_BE_PRIMARY\n  enabled: true\n# Checks if class can be made as data class\n- name: USE_DATA_CLASS\n  enabled: true\n# Checks that never use the name of a variable in the custom getter or setter\n- name: WRONG_NAME_OF_VARIABLE_INSIDE_ACCESSOR\n  enabled: true\n# Checks that classes have only one init block\n- name: MULTIPLE_INIT_BLOCKS\n  enabled: true\n# Checks that there are abstract functions in abstract class\n- name: CLASS_SHOULD_NOT_BE_ABSTRACT\n  enabled: true\n# Checks if there are any trivial getters or setters\n- name: TRIVIAL_ACCESSORS_ARE_NOT_RECOMMENDED\n  enabled: true\n# Checks that no custom getters and setters are used for properties. It is a more wide rule than TRIVIAL_ACCESSORS_ARE_NOT_RECOMMENDED\n# Kotlin compiler automatically generates `get` and `set` methods for properties and also lets the possibility to override it.\n# But in all cases it is very confusing when `get` and `set` are overridden for a developer who uses this particular class.\n# Developer expects to get the value of the property, but receives some unknown value and some extra side effect hidden by the custom getter/setter.\n# Use extra functions for it instead.\n- name: CUSTOM_GETTERS_SETTERS\n  enabled: true\n# Checks if null-check was used explicitly (for example: if (a == null))\n# Try to avoid explicit null checks (explicit comparison with `null`)\n# Kotlin is declared as [Null-safe](https://kotlinlang.org/docs/reference/null-safety.html) language.\n# But Kotlin architects wanted Kotlin to be fully compatible with Java, that's why `null` keyword was also introduced in Kotlin.\n# There are several code-structures that can be used in Kotlin to avoid null-checks. For example: `?:`,  `.let {}`, `.also {}`, e.t.c\n- name: AVOID_NULL_CHECKS\n  enabled: true\n# Checks if class instantiation can be wrapped in `apply` for better readability\n- name: COMPACT_OBJECT_INITIALIZATION\n  enabled: true\n# Checks explicit supertype qualification\n- name: USELESS_SUPERTYPE\n  enabled: true\n# Checks if extension function with the same signature don't have related classes\n- name: EXTENSION_FUNCTION_SAME_SIGNATURE\n  enabled: true\n# Checks if there is empty primary constructor\n- name: EMPTY_PRIMARY_CONSTRUCTOR\n  enabled: true\n# In case of not using field keyword in property accessors,\n# there should be explicit backing property with the name of real property\n# Example: val table get() {if (_table == null) ...} -> table should have _table\n- name: NO_CORRESPONDING_PROPERTY\n  enabled: true\n# Checks if there is class/object that can be replace with extension function\n- name: AVOID_USING_UTILITY_CLASS\n  enabled: true\n# If there is stateless class it is preferred to use object\n- name: OBJECT_IS_PREFERRED\n  enabled: true\n# If there exists negated version of function you should prefer it instead of !functionCall\n- name: INVERSE_FUNCTION_PREFERRED\n  enabled: true\n# Checks if class can be converted to inline class\n- name: INLINE_CLASS_CAN_BE_USED\n  enabled: true\n# If file contains class, then it can't contain extension functions for the same class\n- name: EXTENSION_FUNCTION_WITH_CLASS\n  enabled: true\n# Check if kts script contains other functions except run code\n- name: RUN_IN_SCRIPT\n  enabled: true\n# Check if boolean expression can be simplified\n- name: COMPLEX_BOOLEAN_EXPRESSION\n  enabled: true\n# Check if range can replace with until or `rangeTo` function with range\n- name: CONVENTIONAL_RANGE\n  enabled: true\n  configuration:\n    isRangeToIgnore: false\n# Check if there is a call of print()\\println() or console.log(). Assumption that it's a debug print\n- name: DEBUG_PRINT\n  enabled: true\n# Check that typealias name is in PascalCase\n- name: TYPEALIAS_NAME_INCORRECT_CASE\n  enabled: true\n# Should change property length - 1 to property lastIndex\n- name: USE_LAST_INDEX\n  enabled: true\n# Only properties from the primary constructor should be documented in a @property tag in class KDoc\n- name: KDOC_NO_CLASS_BODY_PROPERTIES_IN_HEADER\n  enabled: true\n"
  },
  {
    "path": "examples/maven/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n         xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd\">\n    <modelVersion>4.0.0</modelVersion>\n    <groupId>com.saveourtool.diktat</groupId>\n    <artifactId>diktat-examples-maven</artifactId>\n    <packaging>pom</packaging>\n    <version>0.0-SNAPSHOT</version>\n\n    <properties>\n        <diktat.version>2.0.0</diktat.version>\n    </properties>\n\n    <!-- This is an example of how DiKTat performs static code analysis.\n\n         If you also wish to compile your code, typically via \"mvn compile\"\n         be sure to follow the instructions at https://kotlinlang.org/docs/maven.html\n         and include the kotlin-maven-plugin. -->\n\n    <build>\n        <plugins>\n            <plugin>\n                <groupId>com.saveourtool.diktat</groupId>\n                <artifactId>diktat-maven-plugin</artifactId>\n                <version>${diktat.version}</version>\n                <configuration>\n                    <diktatConfigFile>diktat-analysis.yml</diktatConfigFile>\n                    <inputs>\n                        <input>${project.basedir}/src/main/kotlin</input>\n                        <input>${project.basedir}/src/test/kotlin</input>\n                    </inputs>\n                </configuration>\n                <executions>\n                    <execution>\n                        <id>diktat</id>\n                        <goals>\n                            <goal>check</goal>\n                            <goal>fix</goal>\n                        </goals>\n                    </execution>\n                </executions>\n            </plugin>\n        </plugins>\n    </build>\n</project>\n"
  },
  {
    "path": "examples/maven/src/main/kotlin/AnotherTest.kt",
    "content": "package whate.ver\n\nfun String.createPluginConfig() {\n    val pluginConfig = TomlDecoder.decode<T>(\n        serializer(),\n        fakeFileNode,\n        DecoderConf()\n    )\n    pluginConfig.configLocation = this.toPath()\n    pluginConfig.prop1 = property1\n    // comment1\n    pluginConfig.configLocation2 = this.toPath()\n    // comment2\n    pluginConfig.prop2 = property2\n}\n"
  },
  {
    "path": "examples/maven/src/main/kotlin/Test.kt",
    "content": "package incorrect\n\nclass incorrectname: Exception() {\n    fun INCORRECT_FUNCTION() {\n        throw Exception()\n    }\n\n    // fun myCommentedFunction() {\n    // }\n\n    val Incorrect_Val = 5\n\n}\n"
  },
  {
    "path": "examples/maven-multiproject/backend/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n         xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd\">\n    <modelVersion>4.0.0</modelVersion>\n    <parent>\n        <groupId>com.saveourtool.diktat</groupId>\n        <artifactId>diktat-examples-maven-multiproject</artifactId>\n        <version>0.0-SNAPSHOT</version>\n        <relativePath>../pom.xml</relativePath>\n    </parent>\n    <artifactId>backend</artifactId>\n</project>\n"
  },
  {
    "path": "examples/maven-multiproject/backend/src/main/kotlin/Test.kt",
    "content": "package incorrect\n\nclass incorrectname: Exception() {\n    fun INCORRECT_FUNCTION() {\n        throw Exception()\n    }\n\n    // fun myCommentedFunction() {\n    // }\n\n    val Incorrect_Val = 5\n\n}\n"
  },
  {
    "path": "examples/maven-multiproject/diktat-analysis.yml",
    "content": "# Common configuration\n- name: DIKTAT_COMMON\n  configuration:\n    # put your package name here - it will be autofixed and checked\n    domainName: your.name.here\n    testDirs: test\n    # expected values:  disabledChapters: \"Naming, Comments, General, Variables, Functions, Classes\"\n    # or: \"1, 2, 3, 4, 5, 6\"\n    disabledChapters: \"\"\n    kotlinVersion: 2.1\n    srcDirectories: \"main\"\n# Checks that the Class/Enum/Interface name matches Pascal case\n- name: CLASS_NAME_INCORRECT\n  enabled: true\n  # all code blocks with MyAnnotation will be ignored and not checked\n  ignoreAnnotated: [ MyAnnotation ]\n# Checks that CONSTANT (treated as const val from companion object or class level) is in non UPPER_SNAKE_CASE\n- name: CONSTANT_UPPERCASE\n  enabled: true\n# Checks that enum value is in upper SNAKE_CASE or in PascalCase depending on the config. UPPER_SNAKE_CASE is the default, but can be changed by 'enumStyle' config\n- name: ENUM_VALUE\n  enabled: true\n  configuration:\n    # Two options: SNAKE_CASE (default), PascalCase\n    enumStyle: SNAKE_CASE\n# Checks that class which extends any Exception class has Exception suffix\n- name: EXCEPTION_SUFFIX\n  enabled: true\n# Checks that file name has extension\n- name: FILE_NAME_INCORRECT\n  enabled: true\n# Checks that file name matches class name, if it is only one class in file\n- name: FILE_NAME_MATCH_CLASS\n  enabled: true\n# Checks that functions/methods which return boolean have special prefix like \"is/should/e.t.c\"\n- name: FUNCTION_BOOLEAN_PREFIX\n  enabled: true\n  configuration:\n    allowedPrefixes: \"\" # A list of functions that return boolean and are allowed to use. Input is in a form \"foo, bar\".\n# Checks that function/method name is in lowerCamelCase\n- name: FUNCTION_NAME_INCORRECT_CASE\n  enabled: true\n# Checks that typealias name is in PascalCase\n- name: TYPEALIAS_NAME_INCORRECT_CASE\n  enabled: true\n# Checks that generic name doesn't contain more than 1 letter (capital). It can be followed by numbers, example: T12, T\n- name: GENERIC_NAME\n  enabled: true\n# Identifier length should be in range [2,64] except names that used in industry like {i, j} and 'e' for catching exceptions\n- name: IDENTIFIER_LENGTH\n  enabled: true\n# Checks that the object matches PascalCase\n- name: OBJECT_NAME_INCORRECT\n  enabled: true\n# Checks that package name is in correct (lower) case\n- name: PACKAGE_NAME_INCORRECT_CASE\n  enabled: true\n# Checks that package name starts with the company's domain\n- name: PACKAGE_NAME_INCORRECT_PREFIX\n  enabled: false\n# Checks that package name does not have incorrect symbols like underscore or non-ASCII letters/digits\n- name: PACKAGE_NAME_INCORRECT_SYMBOLS\n  enabled: true\n# Checks that the path for a file matches with a package name\n- name: PACKAGE_NAME_INCORRECT_PATH\n  enabled: false\n# Checks that package name is in the file\n- name: PACKAGE_NAME_MISSING\n  enabled: true\n# Checks that variable does not have prefix (like mVariable or M_VARIABLE)\n- name: VARIABLE_HAS_PREFIX\n  enabled: true\n# Checks that variable does not contain one single letter, only exceptions are fixed names that used in industry like {i, j}\n- name: VARIABLE_NAME_INCORRECT\n  enabled: true\n# Checks that the name of variable is in lowerCamelCase and contains only ASCII letters\n- name: VARIABLE_NAME_INCORRECT_FORMAT\n  enabled: true\n# Checks that functions have kdoc\n- name: MISSING_KDOC_ON_FUNCTION\n  enabled: true\n# Checks that on file level internal or public class or function has missing KDoc\n- name: MISSING_KDOC_TOP_LEVEL\n  enabled: true\n# Checks that accessible internal elements (protected, public, internal) in a class are documented\n- name: MISSING_KDOC_CLASS_ELEMENTS\n  enabled: true\n# Checks that accessible method parameters are documented in KDoc\n- name: KDOC_WITHOUT_PARAM_TAG\n  enabled: true\n# Checks that accessible method explicit return type is documented in KDoc\n- name: KDOC_WITHOUT_RETURN_TAG\n  enabled: true\n# Checks that accessible method throw keyword is documented in KDoc\n- name: KDOC_WITHOUT_THROWS_TAG\n  enabled: true\n# Checks that KDoc is not empty\n- name: KDOC_EMPTY_KDOC\n  enabled: true\n# Checks that underscore is correctly used to split package naming\n- name: INCORRECT_PACKAGE_SEPARATOR\n  enabled: true\n# Checks that code block doesn't contain kdoc comments\n- name: COMMENTED_BY_KDOC\n  enabled: true\n# Checks that there is no @deprecated tag in kdoc\n- name: KDOC_NO_DEPRECATED_TAG\n  enabled: true\n# Checks that there is no empty content in kdoc tags\n- name: KDOC_NO_EMPTY_TAGS\n  enabled: true\n# Checks that there is only one space after kdoc tag\n- name: KDOC_WRONG_SPACES_AFTER_TAG\n  enabled: true\n# Checks tags order in kDoc. `@param`, `@return`, `@throws`\n- name: KDOC_WRONG_TAGS_ORDER\n  enabled: true\n# Checks that there is no newline of empty KDoc line (with leading asterisk) between `@param`, `@return`, `@throws` tags\n- name: KDOC_NO_NEWLINES_BETWEEN_BASIC_TAGS\n  enabled: true\n# Checks that block of tags @param, @return, @throws is separated from previous part of KDoc by exactly one empty line\n- name: KDOC_NEWLINES_BEFORE_BASIC_TAGS\n  enabled: true\n# Checks that special tags `@apiNote`, `@implNote`, `@implSpec` have exactly one empty line after\n- name: KDOC_NO_NEWLINE_AFTER_SPECIAL_TAGS\n  enabled: true\n# Checks that kdoc does not contain @author tag or date\n- name: KDOC_CONTAINS_DATE_OR_AUTHOR\n  enabled: true\n  configuration:\n    versionRegex: \\d+\\.\\d+\\.\\d+[-.\\w\\d]*\n# Checks that KDoc does not contain single line with words 'return', 'get' or 'set'\n- name: KDOC_TRIVIAL_KDOC_ON_FUNCTION\n  enabled: true\n# Checks that there is newline after header KDoc\n- name: HEADER_WRONG_FORMAT\n  enabled: true\n# Checks that file with zero or >1 classes has header KDoc\n- name: HEADER_MISSING_IN_NON_SINGLE_CLASS_FILE\n  enabled: true\n# Checks that copyright exists on top of file and is properly formatted (as a block comment)\n- name: HEADER_MISSING_OR_WRONG_COPYRIGHT\n  enabled: true\n  configuration:\n    isCopyrightMandatory: false\n    copyrightText: 'Copyright (c) Your Company Name Here. 2010-;@currYear;'\n# Checks that header kdoc is located before package directive\n- name: HEADER_NOT_BEFORE_PACKAGE\n  enabled: true\n# Checks that file does not contain lines > maxSize\n- name: FILE_IS_TOO_LONG\n  enabled: true\n  configuration:\n    # number of lines\n    maxSize: '2000'\n# Checks that file does not contain commented out code\n- name: COMMENTED_OUT_CODE\n  enabled: true\n# Checks that file does not contain only comments, imports and package directive\n- name: FILE_CONTAINS_ONLY_COMMENTS\n  enabled: true\n# Orders imports alphabetically\n- name: FILE_UNORDERED_IMPORTS\n  enabled: true\n  configuration:\n    # use logical imports grouping with sorting inside of a group\n    useRecommendedImportsOrder: true\n# Checks that general order of code parts is right\n- name: FILE_INCORRECT_BLOCKS_ORDER\n  enabled: true\n# Checks that there is exactly one line between code blocks\n- name: FILE_NO_BLANK_LINE_BETWEEN_BLOCKS\n  enabled: true\n# Checks that there is no wildcard imports. Exception: allowedWildcards\n- name: FILE_WILDCARD_IMPORTS\n  enabled: true\n  configuration:\n    allowedWildcards: \"\" # Allowed wildcards for imports (e.g. \"import com.saveourtool.diktat.*, import org.jetbrains.kotlin.*\")\n    useRecommendedImportsOrder: true\n# Checks unused imports\n- name: UNUSED_IMPORT\n  enabled: true\n  configuration:\n    deleteUnusedImport: true\n# Checks that braces are used in if, else, when, for, do, and while statements. Exception: single line ternary operator statement\n- name: NO_BRACES_IN_CONDITIONALS_AND_LOOPS\n  enabled: true\n# Checks that the declaration part of a class-like code structures (class/interface/etc.) is in the proper order\n- name: WRONG_ORDER_IN_CLASS_LIKE_STRUCTURES\n  enabled: true\n# Checks that properties with comments are separated by a blank line\n- name: BLANK_LINE_BETWEEN_PROPERTIES\n  enabled: true\n# Checks top level order\n- name: TOP_LEVEL_ORDER\n  enabled: true\n# Checks that non-empty code blocks with braces follow the K&R style (1TBS or OTBS style)\n- name: BRACES_BLOCK_STRUCTURE_ERROR\n  enabled: true\n  configuration:\n    openBraceNewline: 'True'\n    closeBraceNewline: 'True'\n# Checks that indentation is correct\n- name: WRONG_INDENTATION\n  enabled: true\n  configuration:\n    # Is newline at the end of a file needed\n    newlineAtEnd: true\n    # If true: in parameter list when parameters are split by newline they are indented with two indentations instead of one\n    extendedIndentOfParameters: false\n    # If true: if first parameter in parameter list is on the same line as opening parenthesis, then other parameters can be aligned with it\n    alignedParameters: true\n    # If true, expression bodies which begin on a separate line are indented\n    # using a continuation indent. The default is false.\n    #\n    # This flag is called CONTINUATION_INDENT_FOR_EXPRESSION_BODIES in IDEA and\n    # ij_kotlin_continuation_indent_for_expression_bodies in .editorconfig.\n    extendedIndentForExpressionBodies: false\n    # If true: if expression is split by newline after operator like +/-/`*`, then the next line is indented with two indentations instead of one\n    extendedIndentAfterOperators: true\n    # If true: when dot qualified expression starts on a new line, this line will be indented with two indentations instead of one\n    extendedIndentBeforeDot: false\n    # The indentation size for each file\n    indentationSize: 4\n# Checks that there is no empty blocks in a file.\n# If allowEmptyBlocks is true, checks that it follows correct style (have a newline)\n- name: EMPTY_BLOCK_STRUCTURE_ERROR\n  enabled: true\n  configuration:\n    # Whether a newline after `{` is required in an empty block\n    styleEmptyBlockWithNewline: 'True'\n    allowEmptyBlocks: 'False'\n# Checks that there is no more than one statement per line\n- name: MORE_THAN_ONE_STATEMENT_PER_LINE\n  enabled: true\n# Checks that the line length is < lineLength parameter\n- name: LONG_LINE\n  enabled: true\n  configuration:\n    lineLength: '120'\n# Checks that semicolons are not used at the end of a line\n- name: REDUNDANT_SEMICOLON\n  enabled: true\n# Checks that line breaks follow code style guide: rule 3.6\n- name: WRONG_NEWLINES\n  enabled: true\n  configuration:\n    # If the number of parameters on one line is more than this threshold, all parameters will be placed on separate lines.\n    maxParametersInOneLine: 2\n    # 3 by default.\n    maxCallsInOneLine: 3\n# Checks trailing comma\n- name: TRAILING_COMMA\n  enabled: true\n  configuration:\n    # VALUE_ARGUMENT\n    valueArgument: false\n    # VALUE_PARAMETER\n    valueParameter: false\n    # REFERENCE_EXPRESSION\n    indices: false\n    # WHEN_CONDITION_WITH_EXPRESSION\n    whenConditions: false\n    # STRING_TEMPLATE\n    collectionLiteral: false\n    # TYPE_PROJECTION\n    typeArgument: false\n    # TYPE_PARAMETER\n    typeParameter: false\n    # DESTRUCTURING_DECLARATION_ENTRY\n    destructuringDeclaration: false\n# Checks that there are not too many consecutive spaces in line\n- name: TOO_MANY_CONSECUTIVE_SPACES\n  enabled: true\n  configuration:\n    # Maximum allowed number of consecutive spaces (not counting indentation)\n    maxSpaces: '1'\n    # Whether formatting for enums should be kept without checking\n    saveInitialFormattingForEnums: false\n# Inspection that checks if a long dot qualified expression is used in condition or as an argument\n- name: COMPLEX_EXPRESSION\n  enabled: true\n# Checks that blank lines are used correctly.\n# For example: triggers when there are too many blank lines between function declaration\n- name: TOO_MANY_BLANK_LINES\n  enabled: true\n# Checks that usage of horizontal spaces doesn't violate code style guide\n- name: WRONG_WHITESPACE\n  enabled: true\n# Checks that backticks (``) are not used in the identifier name, except the case when it is test method (marked with @Test annotation)\n- name: BACKTICKS_PROHIBITED\n  enabled: true\n# Checks that a single line concatenation of strings is not used\n- name: STRING_CONCATENATION\n  enabled: true\n# Checks that each when statement have else in the end\n- name: WHEN_WITHOUT_ELSE\n  enabled: true\n# Checks that annotation is on a single line\n- name: ANNOTATION_NEW_LINE\n  enabled: true\n# Checks that method annotated with `Preview` annotation is private and has Preview suffix\n- name: PREVIEW_ANNOTATION\n  enabled: true\n# Checks that enum structure is correct: enum entries should be separated by comma and line break and last entry should have semicolon in the end.\n- name: ENUMS_SEPARATED\n  enabled: true\n# Checks that value on integer or float constant is not too big\n- name: LONG_NUMERICAL_VALUES_SEPARATED\n  enabled: true\n  configuration:\n    # Maximum number of digits which are not split\n    maxNumberLength: '5'\n    # Maximum number of digits between separators\n    maxBlockLength: '3'\n# Checks magic number\n- name: MAGIC_NUMBER\n  enabled: true\n  configuration:\n    # Ignore numbers from test\n    ignoreTest: \"true\"\n    # Ignore numbers\n    ignoreNumbers: \"-1, 1, 0, 2, 0U, 1U, 2U, -1L, 0L, 1L, 2L, 0UL, 1UL, 2UL\"\n    # Is ignore override hashCode function\n    ignoreHashCodeFunction: \"true\"\n    # Is ignore property\n    ignorePropertyDeclaration: \"false\"\n    # Is ignore local variable\n    ignoreLocalVariableDeclaration: \"false\"\n    # Is ignore value parameter\n    ignoreValueParameter: \"true\"\n    # Is ignore constant\n    ignoreConstantDeclaration: \"true\"\n    # Is ignore property in companion object\n    ignoreCompanionObjectPropertyDeclaration: \"true\"\n    # Is ignore numbers in enum\n    ignoreEnums: \"false\"\n    # Is ignore number in ranges\n    ignoreRanges: \"false\"\n    # Is ignore number in extension function\n    ignoreExtensionFunctions: \"false\"\n    # Is ignore number in pairs created using to\n    ignorePairsCreatedUsingTo: \"false\"\n# Checks that order of enum values or constant property inside companion is correct\n- name: WRONG_DECLARATIONS_ORDER\n  enabled: true\n  configuration:\n    # Whether enum members should be sorted alphabetically\n    sortEnum: true\n    # Whether class properties should be sorted alphabetically\n    sortProperty: true\n# Checks that multiple modifiers sequence is in the correct order\n- name: WRONG_MULTIPLE_MODIFIERS_ORDER\n  enabled: true\n# Checks that identifier has appropriate name (See table of rule 1.2 part 6)\n- name: CONFUSING_IDENTIFIER_NAMING\n  enabled: true\n# Checks year in the copyright\n- name: WRONG_COPYRIGHT_YEAR\n  enabled: true\n# Inspection that checks if local variables are declared close to the first usage site\n- name: LOCAL_VARIABLE_EARLY_DECLARATION\n  enabled: true\n# Try to avoid initialize val by null (e.g. val a: Int? = null -> val a: Int = 0)\n- name: NULLABLE_PROPERTY_TYPE\n  enabled: true\n# Inspection that checks if there is a blank line before kDoc and none after\n- name: WRONG_NEWLINES_AROUND_KDOC\n  enabled: true\n# Inspection that checks if there is no blank lines before first comment\n- name: FIRST_COMMENT_NO_BLANK_LINE\n  enabled: true\n# Inspection that checks if there are blank lines between code and comment and between code start token and comment's text\n- name: COMMENT_WHITE_SPACE\n  enabled: true\n  configuration:\n    maxSpacesBeforeComment: 2\n    maxSpacesInComment: 1\n# Inspection that checks if all comment's are inside if-else code blocks. Exception is general if comment\n- name: IF_ELSE_COMMENTS\n  enabled: true\n# Type aliases provide alternative names for existing types when type's reference text is longer 25 chars\n- name: TYPE_ALIAS\n  enabled: true\n  configuration:\n    typeReferenceLength: '25' # max length of type reference\n# Checks if casting can be omitted\n- name: SMART_CAST_NEEDED\n  enabled: true\n# Checks that variables of generic types have explicit type declaration\n- name: GENERIC_VARIABLE_WRONG_DECLARATION\n  enabled: true\n# Inspection that checks if string template has redundant curly braces\n- name: STRING_TEMPLATE_CURLY_BRACES\n  enabled: true\n# Variables with `val` modifier - are immutable (read-only). Usage of such variables instead of `var` variables increases\n# robustness and readability of code, because `var` variables can be reassigned several times in the business logic.\n# This rule prohibits usage of `var`s as local variables - the only exception is accumulators and counters\n- name: SAY_NO_TO_VAR\n  enabled: true\n# Inspection that checks if string template has redundant quotes\n- name: STRING_TEMPLATE_QUOTES\n  enabled: true\n# Check if there are redundant nested if-statements, which could be collapsed into a single one by concatenating their conditions\n- name: COLLAPSE_IF_STATEMENTS\n  enabled: true\n  configuration:\n    startCollapseFromNestedLevel: 2\n# Checks that floating-point values are not used in arithmetic expressions\n- name: FLOAT_IN_ACCURATE_CALCULATIONS\n  enabled: true\n# Checks that function length isn't too long\n- name: TOO_LONG_FUNCTION\n  enabled: true\n  configuration:\n    maxFunctionLength: '30' # max length of function\n    isIncludeHeader: 'false' # count function's header\n# Warns if there are nested functions\n- name: AVOID_NESTED_FUNCTIONS\n  enabled: true\n# Checks that lambda inside function parameters is in the end\n- name: LAMBDA_IS_NOT_LAST_PARAMETER\n  enabled: true\n# Checks that function doesn't contains too many parameters\n- name: TOO_MANY_PARAMETERS\n  enabled: true\n  configuration:\n    maxParameterListSize: '5' # max parameters size\n# Checks that function doesn't have too many nested blocks\n- name: NESTED_BLOCK\n  enabled: true\n  configuration:\n    maxNestedBlockQuantity: '4'\n# Checks that function use default values, instead overloading\n- name: WRONG_OVERLOADING_FUNCTION_ARGUMENTS\n  enabled: true\n# Checks that using runBlocking inside async block code\n- name: RUN_BLOCKING_INSIDE_ASYNC\n  enabled: true\n# Checks that property in constructor doesn't contain comment\n- name: KDOC_NO_CONSTRUCTOR_PROPERTY\n  enabled: true\n  configuration:\n    isParamTagsForParameters: true # create param tags for parameters without val or var\n    isParamTagsForPrivateProperties: true # create param tags for private properties\n    isParamTagsForGenericTypes: true # create param tags for generic types\n# Checks that the long lambda has parameters\n- name: TOO_MANY_LINES_IN_LAMBDA\n  enabled: true\n  configuration:\n    maxLambdaLength: 10 # max length of lambda without parameters\n# Checks that using unnecessary, custom label\n- name: CUSTOM_LABEL\n  enabled: true\n# Check that lambda with inner lambda doesn't use implicit parameter\n- name: PARAMETER_NAME_IN_OUTER_LAMBDA\n  enabled: true\n# Checks that property in KDoc present in class\n- name: KDOC_EXTRA_PROPERTY\n  enabled: true\n# There's a property in KDoc which is already present\n- name: KDOC_DUPLICATE_PROPERTY\n  enabled: true\n# Checks that KDoc in constructor has property tag but with comment inside constructor\n- name: KDOC_NO_CONSTRUCTOR_PROPERTY_WITH_COMMENT\n  enabled: true\n# if a class has single constructor, it should be converted to a primary constructor\n- name: SINGLE_CONSTRUCTOR_SHOULD_BE_PRIMARY\n  enabled: true\n# Checks if class can be made as data class\n- name: USE_DATA_CLASS\n  enabled: true\n# Checks that never use the name of a variable in the custom getter or setter\n- name: WRONG_NAME_OF_VARIABLE_INSIDE_ACCESSOR\n  enabled: true\n# Checks that classes have only one init block\n- name: MULTIPLE_INIT_BLOCKS\n  enabled: true\n# Checks that there are abstract functions in abstract class\n- name: CLASS_SHOULD_NOT_BE_ABSTRACT\n  enabled: true\n# Checks if there are any trivial getters or setters\n- name: TRIVIAL_ACCESSORS_ARE_NOT_RECOMMENDED\n  enabled: true\n# Checks that no custom getters and setters are used for properties. It is a more wide rule than TRIVIAL_ACCESSORS_ARE_NOT_RECOMMENDED\n# Kotlin compiler automatically generates `get` and `set` methods for properties and also lets the possibility to override it.\n# But in all cases it is very confusing when `get` and `set` are overridden for a developer who uses this particular class.\n# Developer expects to get the value of the property, but receives some unknown value and some extra side effect hidden by the custom getter/setter.\n# Use extra functions for it instead.\n- name: CUSTOM_GETTERS_SETTERS\n  enabled: true\n# Checks if null-check was used explicitly (for example: if (a == null))\n# Try to avoid explicit null checks (explicit comparison with `null`)\n# Kotlin is declared as [Null-safe](https://kotlinlang.org/docs/reference/null-safety.html) language.\n# But Kotlin architects wanted Kotlin to be fully compatible with Java, that's why `null` keyword was also introduced in Kotlin.\n# There are several code-structures that can be used in Kotlin to avoid null-checks. For example: `?:`,  `.let {}`, `.also {}`, e.t.c\n- name: AVOID_NULL_CHECKS\n  enabled: true\n# Checks if class instantiation can be wrapped in `apply` for better readability\n- name: COMPACT_OBJECT_INITIALIZATION\n  enabled: true\n# Checks explicit supertype qualification\n- name: USELESS_SUPERTYPE\n  enabled: true\n# Checks if extension function with the same signature don't have related classes\n- name: EXTENSION_FUNCTION_SAME_SIGNATURE\n  enabled: true\n# Checks if there is empty primary constructor\n- name: EMPTY_PRIMARY_CONSTRUCTOR\n  enabled: true\n# In case of not using field keyword in property accessors,\n# there should be explicit backing property with the name of real property\n# Example: val table get() {if (_table == null) ...} -> table should have _table\n- name: NO_CORRESPONDING_PROPERTY\n  enabled: true\n# Checks if there is class/object that can be replace with extension function\n- name: AVOID_USING_UTILITY_CLASS\n  enabled: true\n# If there is stateless class it is preferred to use object\n- name: OBJECT_IS_PREFERRED\n  enabled: true\n# If there exists negated version of function you should prefer it instead of !functionCall\n- name: INVERSE_FUNCTION_PREFERRED\n  enabled: true\n# Checks if class can be converted to inline class\n- name: INLINE_CLASS_CAN_BE_USED\n  enabled: true\n# If file contains class, then it can't contain extension functions for the same class\n- name: EXTENSION_FUNCTION_WITH_CLASS\n  enabled: true\n# Check if kts script contains other functions except run code\n- name: RUN_IN_SCRIPT\n  enabled: true\n# Check if boolean expression can be simplified\n- name: COMPLEX_BOOLEAN_EXPRESSION\n  enabled: true\n# Check if range can replace with until or `rangeTo` function with range\n- name: CONVENTIONAL_RANGE\n  enabled: true\n  configuration:\n    isRangeToIgnore: false\n# Check if there is a call of print()\\println() or console.log(). Assumption that it's a debug print\n- name: DEBUG_PRINT\n  enabled: true\n# Check that typealias name is in PascalCase\n- name: TYPEALIAS_NAME_INCORRECT_CASE\n  enabled: true\n# Should change property length - 1 to property lastIndex\n- name: USE_LAST_INDEX\n  enabled: true\n# Only properties from the primary constructor should be documented in a @property tag in class KDoc\n- name: KDOC_NO_CLASS_BODY_PROPERTIES_IN_HEADER\n  enabled: true\n"
  },
  {
    "path": "examples/maven-multiproject/frontend/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n         xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd\">\n    <modelVersion>4.0.0</modelVersion>\n    <parent>\n        <groupId>com.saveourtool.diktat</groupId>\n        <artifactId>diktat-examples-maven-multiproject</artifactId>\n        <version>0.0-SNAPSHOT</version>\n        <relativePath>../pom.xml</relativePath>\n    </parent>\n    <artifactId>frontend</artifactId>\n</project>\n"
  },
  {
    "path": "examples/maven-multiproject/frontend/src/main/kotlin/AnotherTest.kt",
    "content": "package whate.ver\n\nfun String.createPluginConfig() {\n    val pluginConfig = TomlDecoder.decode<T>(\n        serializer(),\n        fakeFileNode,\n        DecoderConf()\n    )\n    pluginConfig.configLocation = this.toPath()\n    pluginConfig.prop1 = property1\n    // comment1\n    pluginConfig.configLocation2 = this.toPath()\n    // comment2\n    pluginConfig.prop2 = property2\n}\n"
  },
  {
    "path": "examples/maven-multiproject/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n         xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd\">\n    <modelVersion>4.0.0</modelVersion>\n    <groupId>com.saveourtool.diktat</groupId>\n    <artifactId>diktat-examples-maven-multiproject</artifactId>\n    <packaging>pom</packaging>\n    <version>0.0-SNAPSHOT</version>\n\n    <properties>\n        <diktat.version>2.0.0</diktat.version>\n    </properties>\n\n    <!-- This is an example of how DiKTat performs static code analysis.\n\n         If you also wish to compile your code, typically via \"mvn compile\"\n         be sure to follow the instructions at https://kotlinlang.org/docs/maven.html\n         and include the kotlin-maven-plugin. -->\n\n    <build>\n        <plugins>\n            <plugin>\n                <groupId>com.saveourtool.diktat</groupId>\n                <artifactId>diktat-maven-plugin</artifactId>\n                <version>${diktat.version}</version>\n                <configuration>\n                    <diktatConfigFile>diktat-analysis.yml</diktatConfigFile>\n                    <inputs>\n                        <input>${project.basedir}/src/main/kotlin</input>\n                        <input>${project.basedir}/src/test/kotlin</input>\n                    </inputs>\n                </configuration>\n                <executions>\n                    <execution>\n                        <id>diktat</id>\n                        <goals>\n                            <goal>check</goal>\n                            <goal>fix</goal>\n                        </goals>\n                    </execution>\n                </executions>\n            </plugin>\n        </plugins>\n    </build>\n\n    <modules>\n        <module>backend</module>\n        <module>frontend</module>\n    </modules>\n</project>\n"
  },
  {
    "path": "gradle/libs.versions.toml",
    "content": "[versions]\nkotlin = \"2.1.0\"\nkotlin-ksp = \"2.1.0-1.0.29\"\nserialization = \"1.6.3\"\nktlint = \"1.5.0\"\njunit = \"5.10.2\"\njunit-platfrom = \"1.10.2\"\nguava = \"33.0.0-jre\"\ncommons-cli = \"1.6.0\"\ncommons-io = \"2.15.1\"\ndetekt = \"1.23.5\"\ndokka = \"1.9.20\"\ngradle-nexus-publish-plugin = \"2.0.0\"\njacoco = \"0.8.8\"\n# maven\nmaven-api = \"3.9.6\"\nmaven-plugin-tools = \"3.8.1\"\nmaven-plugin-testing-harness = \"3.3.0\"\nplexus = \"3.0.0\"\n\njbool = \"1.24\"\nkotlin-logging = \"6.0.3\"\nlog4j2 = \"2.23.1\"\nkaml = \"0.57.0\"\nsarif4k = \"0.6.0\"\njupiter-itf-extension = \"0.13.1\"\n\n# executable jar\nkotlinx-cli = \"0.3.6\"\ngradle-shadow = \"8.1.1\"\n\n# copied from save-cloud\njetbrains-annotations = \"26.0.1\"\nkotlinx-coroutines = \"1.8.0\"\nassertj = \"3.25.3\"\ndiktat = \"2.0.0\"\nreckon = \"0.18.3\"\nspotless = \"6.25.0\"\ndownload = \"5.6.0\"\n\n[plugins]\nkotlin-jvm = { id = \"org.jetbrains.kotlin.jvm\", version.ref = \"kotlin\" }\nkotlin-js = { id = \"org.jetbrains.kotlin.js\", version.ref = \"kotlin\" }\nkotlin-multiplatform = { id = \"org.jetbrains.kotlin.multiplatform\", version.ref = \"kotlin\" }\nkotlin-plugin-serialization = { id = \"org.jetbrains.kotlin.plugin.serialization\", version.ref = \"kotlin\" }\nkotlin-plugin-jpa = { id = \"org.jetbrains.kotlin.plugin.jpa\", version.ref = \"kotlin\" }\nkotlin-plugin-allopen = { id = \"org.jetbrains.kotlin.plugin.allopen\", version.ref = \"kotlin\" }\nkotlin-ksp = { id = \"com.google.devtools.ksp\", version.ref = \"kotlin-ksp\" }\ntalaiot-base = { id = \"io.github.cdsap.talaiot.plugin.base\", version = \"2.0.4\" }\ndetekt = { id = \"io.gitlab.arturbosch.detekt\", version.ref = \"detekt\" }\nspotless = { id = \"com.diffplug.gradle.spotless\", version.ref = \"spotless\" }\ndownload = { id = \"de.undercouch.download\", version.ref = \"download\" }\nshadow = { id = \"com.github.johnrengelman.shadow\", version.ref = \"gradle-shadow\" }\n\n[libraries]\n# plugins as dependency\ndokka-gradle-plugin = { module = \"org.jetbrains.dokka:dokka-gradle-plugin\", version.ref = \"dokka\" }\ngradle-nexus-publish-plugin = { module = \"io.github.gradle-nexus:publish-plugin\", version.ref = \"gradle-nexus-publish-plugin\"}\ndownload-plugin = { module = \"de.undercouch:gradle-download-task\", version.ref = \"download\" }\n\n# kotlin\nkotlin-stdlib = { module = \"org.jetbrains.kotlin:kotlin-stdlib\", version.ref = \"kotlin\" }\nkotlin-stdlib-common = { module = \"org.jetbrains.kotlin:kotlin-stdlib-common\", version.ref = \"kotlin\" }\nkotlin-stdlib-jdk7 = { module = \"org.jetbrains.kotlin:kotlin-stdlib-jdk7\", version.ref = \"kotlin\" }\nkotlin-stdlib-jdk8 = { module = \"org.jetbrains.kotlin:kotlin-stdlib-jdk8\", version.ref = \"kotlin\" }\nkotlin-compiler-embeddable = { module = \"org.jetbrains.kotlin:kotlin-compiler-embeddable\", version.ref = \"kotlin\" }\nkotlin-reflect = { module = \"org.jetbrains.kotlin:kotlin-reflect\", version.ref = \"kotlin\" }\n\n# ksp\nkotlin-ksp-api = { module = \"com.google.devtools.ksp:symbol-processing-api\", version.ref = \"kotlin-ksp\" }\n\n# kotlinx serialization\nkotlinx-serialization-core = { module = \"org.jetbrains.kotlinx:kotlinx-serialization-core\", version.ref = \"serialization\" }\nkotlinx-serialization-json = { module = \"org.jetbrains.kotlinx:kotlinx-serialization-json\", version.ref = \"serialization\" }\nkotlinx-serialization-json-jvm = { module = \"org.jetbrains.kotlinx:kotlinx-serialization-json-jvm\", version.ref = \"serialization\" }\n# another serialization\nkaml = { module = \"com.charleskorn.kaml:kaml\", version.ref = \"kaml\" }\n\n# kotlinx coroutines\nkotlinx-coroutines-core = { module = \"org.jetbrains.kotlinx:kotlinx-coroutines-core\", version.ref = \"kotlinx-coroutines\" }\n\n#kotlin libs\n\n# ktlint & detekt\nktlint-rule-engine = { module = \"com.pinterest.ktlint:ktlint-rule-engine\", version.ref = \"ktlint\" }\nktlint-rule-engine-core = { module = \"com.pinterest.ktlint:ktlint-rule-engine-core\", version.ref = \"ktlint\" }\nktlint-logger = { module = \"com.pinterest.ktlint:ktlint-logger\", version.ref = \"ktlint\" }\nktlint-cli-ruleset-core = { module = \"com.pinterest.ktlint:ktlint-cli-ruleset-core\", version.ref = \"ktlint\" }\nktlint-cli-reporter-core = { module = \"com.pinterest.ktlint:ktlint-cli-reporter-core\", version.ref = \"ktlint\" }\nktlint-cli-reporter-baseline = { module = \"com.pinterest.ktlint:ktlint-cli-reporter-baseline\", version.ref = \"ktlint\" }\nktlint-cli-reporter-checkstyle = { module = \"com.pinterest.ktlint:ktlint-cli-reporter-checkstyle\", version.ref = \"ktlint\" }\nktlint-cli-reporter-html = { module = \"com.pinterest.ktlint:ktlint-cli-reporter-html\", version.ref = \"ktlint\" }\nktlint-cli-reporter-json = { module = \"com.pinterest.ktlint:ktlint-cli-reporter-json\", version.ref = \"ktlint\" }\nktlint-cli-reporter-plain = { module = \"com.pinterest.ktlint:ktlint-cli-reporter-plain\", version.ref = \"ktlint\" }\nktlint-cli-reporter-sarif = { module = \"com.pinterest.ktlint:ktlint-cli-reporter-sarif\", version.ref = \"ktlint\" }\nsarif4k = { module = \"io.github.detekt.sarif4k:sarif4k\", version.ref = \"sarif4k\" }\nsarif4k-jvm = { module = \"io.github.detekt.sarif4k:sarif4k-jvm\", version.ref = \"sarif4k\" }\n\n# apache\napache-commons-cli = { module = \"commons-cli:commons-cli\", version.ref = \"commons-cli\" }\napache-commons-io = { module = \"commons-io:commons-io\", version.ref = \"commons-io\" }\n\n# others\nguava = { module = \"com.google.guava:guava\", version.ref = \"guava\" }\njbool-expressions = { module = \"com.bpodgursky:jbool_expressions\", version.ref = \"jbool\" }\n\n# logging\nkotlin-logging = { module = \"io.github.oshai:kotlin-logging\", version.ref = \"kotlin-logging\" }\nslf4j-api = { module = \"org.slf4j:slf4j-api\", version = \"2.0.12\" }\nlog4j2-core = { module = \"org.apache.logging.log4j:log4j-core\", version.ref = \"log4j2\" }\nlog4j2-slf4j2 = { module = \"org.apache.logging.log4j:log4j-slf4j2-impl\", version.ref = \"log4j2\" }\n\n# cli\nkotlinx-cli = { module = \"org.jetbrains.kotlinx:kotlinx-cli\", version.ref = \"kotlinx-cli\" }\n\n# testing\njunit-jupiter = { module = \"org.junit.jupiter:junit-jupiter\", version.ref = \"junit\" }\njunit-jupiter-engine = { module = \"org.junit.jupiter:junit-jupiter-engine\", version.ref = \"junit\" }\njunit-jupiter-api = { module = \"org.junit.jupiter:junit-jupiter-api\", version.ref = \"junit\" }\njunit-vintage-engine = { module = \"org.junit.vintage:junit-vintage-engine\", version.ref = \"junit\" }\njunit-jupiter-extension-itf = { module = \"com.soebes.itf.jupiter.extension:itf-jupiter-extension\", version.ref = \"jupiter-itf-extension\" }\nassertj-core = { module = \"org.assertj:assertj-core\", version.ref = \"assertj\" }\njunit-platform-suite = { module = \"org.junit.platform:junit-platform-suite-engine\", version.ref = \"junit-platfrom\" }\n\n# maven\nmaven-core = { module = \"org.apache.maven:maven-core\", version.ref = \"maven-api\" }\nmaven-compat = { module = \"org.apache.maven:maven-compat\", version.ref = \"maven-api\" }\nmaven-plugin-annotations = { module = \"org.apache.maven.plugin-tools:maven-plugin-annotations\", version.ref = \"maven-plugin-tools\" }\nmaven-plugin-testing-harness = { module = \"org.apache.maven.plugin-testing:maven-plugin-testing-harness\", version.ref = \"maven-plugin-testing-harness\" }\nplexus-cipher = { module = \"org.codehaus.plexus:plexus-cipher\", version.ref = \"plexus\" }\n\n######### copied from save-cloud\nkotlin-gradle-plugin = { module = \"org.jetbrains.kotlin:kotlin-gradle-plugin\", version.ref = \"kotlin\" }\nkotlin-plugin-serialization = { module = \"org.jetbrains.kotlin:kotlin-serialization\", version.ref = \"kotlin\" }\n\n\njetbrains-annotations = { module = \"org.jetbrains:annotations\", version.ref = \"jetbrains-annotations\" }\n\n# java core libraries\nvalidation-api = { module = \"jakarta.validation:jakarta.validation-api\"}\nannotation-api = { module = \"jakarta.annotation:jakarta.annotation-api\"}\n\n# code quality\ndiktat-gradle-plugin = { module = \"com.saveourtool.diktat:diktat-gradle-plugin\", version.ref = \"diktat\" }\ndetekt-gradle-plugin = { module = \"io.gitlab.arturbosch.detekt:detekt-gradle-plugin\", version.ref = \"detekt\" }\ngradle-plugin-spotless = { module = \"com.diffplug.spotless:spotless-plugin-gradle\", version.ref = \"spotless\" }\nreckon-gradle-plugin = { module = \"org.ajoberstar.reckon:reckon-gradle\", version.ref = \"reckon\" }\n"
  },
  {
    "path": "gradle/plugins/build.gradle.kts",
    "content": "import org.jetbrains.kotlin.gradle.tasks.KotlinCompile\n\nplugins {\n    `kotlin-dsl`\n}\n\nrepositories {\n    file(\"$rootDir/../../build/diktat-snapshot\")\n        .takeIf { it.exists() }\n        ?.run {\n            maven {\n                url = this@run.toURI()\n            }\n        }\n    maven {\n        url = uri(\"https://s01.oss.sonatype.org/content/repositories/snapshots/\")\n        content {\n            includeGroup(\"com.saveourtool.diktat\")\n        }\n    }\n    mavenCentral()\n    gradlePluginPortal()\n}\n\ntasks.withType<KotlinCompile> {\n    compilerOptions {\n        freeCompilerArgs.add(\"-opt-in=kotlin.RequiresOptIn\")\n    }\n}\n\nrun {\n    @Suppress(\"COMMENTED_OUT_CODE\", \"WRONG_INDENTATION\")\n    dependencies {\n        // workaround https://github.com/gradle/gradle/issues/15383\n        implementation(files(project.libs.javaClass.superclass.protectionDomain.codeSource.location))\n        implementation(libs.kotlin.gradle.plugin)\n        implementation(libs.reckon.gradle.plugin)\n        implementation(libs.detekt.gradle.plugin) {\n            exclude(\"io.github.detekt.sarif4k\", \"sarif4k\")\n        }\n        implementation(libs.diktat.gradle.plugin) {\n            exclude(\"io.github.detekt.sarif4k\", \"sarif4k\")\n        }\n        implementation(libs.sarif4k)\n        implementation(libs.gradle.plugin.spotless)\n        implementation(libs.dokka.gradle.plugin)\n        implementation(libs.gradle.nexus.publish.plugin)\n        // extra dependencies\n        implementation(libs.kotlin.stdlib)\n        implementation(libs.kotlin.stdlib.common)\n        implementation(libs.kotlin.stdlib.jdk7)\n        implementation(libs.kotlin.stdlib.jdk8)\n        implementation(libs.jetbrains.annotations)\n    }\n}\n"
  },
  {
    "path": "gradle/plugins/settings.gradle.kts",
    "content": "rootProject.name = \"buildutils\"\n\ndependencyResolutionManagement {\n    versionCatalogs {\n        create(\"libs\") {\n            from(files(\"../libs.versions.toml\"))\n        }\n    }\n}\n"
  },
  {
    "path": "gradle/plugins/src/main/kotlin/Versions.kt",
    "content": "@file:Suppress(\"CONSTANT_UPPERCASE\", \"PACKAGE_NAME_MISSING\")\n\nobject Versions {\n    /**\n     * JDK version which is used for building and running the project.\n     */\n    const val jdk = \"8\"\n}\n"
  },
  {
    "path": "gradle/plugins/src/main/kotlin/com/saveourtool/diktat/buildutils/JacocoConfiguration.kt",
    "content": "/**\n * Configuration for code coverage calculation via Jacoco\n */\n\npackage com.saveourtool.diktat.buildutils\n\nimport org.gradle.accessors.dm.LibrariesForLibs\nimport org.gradle.api.Project\nimport org.gradle.api.tasks.testing.Test\nimport org.gradle.kotlin.dsl.apply\nimport org.gradle.kotlin.dsl.configure\nimport org.gradle.kotlin.dsl.named\nimport org.gradle.kotlin.dsl.the\nimport org.gradle.testing.jacoco.plugins.JacocoPlugin\nimport org.gradle.testing.jacoco.plugins.JacocoPluginExtension\nimport org.gradle.testing.jacoco.tasks.JacocoReport\n\n/**\n * Configure jacoco for [this] project\n */\nfun Project.configureJacoco() {\n    apply<JacocoPlugin>()\n\n    configure<JacocoPluginExtension> {\n        toolVersion = the<LibrariesForLibs>()\n            .versions\n            .jacoco\n            .get()\n    }\n\n    tasks.named<Test>(\"test\") {\n        finalizedBy(\"jacocoTestReport\")\n    }\n    tasks.named<JacocoReport>(\"jacocoTestReport\") {\n        dependsOn(tasks.named<Test>(\"test\"))\n        reports {\n            xml.required.set(true)\n            html.required.set(true)\n        }\n    }\n}\n"
  },
  {
    "path": "gradle/plugins/src/main/kotlin/com/saveourtool/diktat/buildutils/PublishingConfiguration.kt",
    "content": "/**\n * Publishing configuration file.\n */\n\n@file:Suppress(\n    \"MISSING_KDOC_TOP_LEVEL\",\n    \"MISSING_KDOC_ON_FUNCTION\",\n)\n\npackage com.saveourtool.diktat.buildutils\n\nimport io.github.gradlenexus.publishplugin.NexusPublishExtension\nimport io.github.gradlenexus.publishplugin.NexusPublishPlugin\nimport org.gradle.api.Named\nimport org.gradle.api.Project\nimport org.gradle.api.publish.PublishingExtension\nimport org.gradle.api.publish.maven.MavenPom\nimport org.gradle.api.publish.maven.MavenPublication\nimport org.gradle.api.publish.maven.plugins.MavenPublishPlugin\nimport org.gradle.api.publish.maven.tasks.PublishToMavenRepository\nimport org.gradle.api.tasks.bundling.Jar\nimport org.gradle.internal.logging.text.StyledTextOutput\nimport org.gradle.internal.logging.text.StyledTextOutput.Style.Failure\nimport org.gradle.internal.logging.text.StyledTextOutput.Style.Success\nimport org.gradle.internal.logging.text.StyledTextOutputFactory\nimport org.gradle.kotlin.dsl.apply\nimport org.gradle.kotlin.dsl.configure\nimport org.gradle.kotlin.dsl.extra\nimport org.gradle.kotlin.dsl.getByType\nimport org.gradle.kotlin.dsl.register\nimport org.gradle.kotlin.dsl.support.serviceOf\nimport org.gradle.kotlin.dsl.withType\nimport org.gradle.plugins.signing.Sign\nimport org.gradle.plugins.signing.SigningExtension\nimport org.gradle.plugins.signing.SigningPlugin\nimport org.jetbrains.dokka.gradle.DokkaPlugin\n\n/**\n * Configures all aspects of the publishing process.\n */\nfun Project.configurePublishing() {\n    apply<MavenPublishPlugin>()\n    if (this == rootProject) {\n        configureNexusPublishing()\n        configureGitHubPublishing()\n    }\n\n    afterEvaluate {\n        configureSigning()\n    }\n}\n\n/**\n * Configures _pom.xml_\n *\n * @param project\n */\n@Suppress(\"TOO_LONG_FUNCTION\")\nfun MavenPom.configurePom(project: Project) {\n    name.set(project.name)\n    description.set(project.description ?: project.name)\n    url.set(\"https://github.com/saveourtool/diktat\")\n    licenses {\n        license {\n            name.set(\"MIT License\")\n            url.set(\"https://opensource.org/license/MIT\")\n            distribution.set(\"repo\")\n        }\n    }\n    developers {\n        developer {\n            id.set(\"akuleshov7\")\n            name.set(\"Andrey Kuleshov\")\n            email.set(\"andrewkuleshov7@gmail.com\")\n            url.set(\"https://github.com/akuleshov7\")\n        }\n        developer {\n            id.set(\"petertrr\")\n            name.set(\"Peter Trifanov\")\n            email.set(\"peter.trifanov@gmail.com\")\n            url.set(\"https://github.com/petertrr\")\n        }\n        developer {\n            id.set(\"nulls\")\n            name.set(\"Nariman Abdullin\")\n            email.set(\"nulls.narik@gmail.com\")\n            url.set(\"https://github.com/nulls\")\n        }\n    }\n    scm {\n        url.set(\"https://github.com/saveourtool/diktat\")\n        connection.set(\"scm:git:git://github.com/saveourtool/diktat.git\")\n        developerConnection.set(\"scm:git:git@github.com:saveourtool/diktat.git\")\n    }\n}\n\n/**\n * Configures all publications. The publications must already exist.\n */\n@Suppress(\"TOO_LONG_FUNCTION\")\nfun Project.configurePublications() {\n    if (this == rootProject) {\n        return\n    }\n    val sourcesJar = tasks.named(SOURCES_JAR)\n    apply<DokkaPlugin>()\n    @Suppress(\"GENERIC_VARIABLE_WRONG_DECLARATION\")\n    val dokkaJarProvider = tasks.register<Jar>(\"dokkaJar\") {\n        group = \"documentation\"\n        archiveClassifier.set(\"javadoc\")\n        from(tasks.named(\"dokkaHtml\"))\n    }\n    configure<PublishingExtension> {\n        repositories {\n            mavenLocal()\n        }\n        publications.withType<MavenPublication>().configureEach {\n            artifact(sourcesJar)\n            artifact(dokkaJarProvider)\n            pom {\n                configurePom(project)\n            }\n        }\n    }\n}\n\n/**\n * Configures Maven Central as the publish destination.\n */\n@Suppress(\"TOO_LONG_FUNCTION\")\nprivate fun Project.configureNexusPublishing() {\n    setPropertyFromEnv(\"OSSRH_USERNAME\", \"sonatypeUsername\")\n    setPropertyFromEnv(\"OSSRH_PASSWORD\", \"sonatypePassword\")\n\n    if (!hasProperties(\"sonatypeUsername\", \"sonatypePassword\")) {\n        styledOut(logCategory = \"nexus\")\n            .style(StyledTextOutput.Style.Info)\n            .text(\"Skipping Nexus publishing configuration as either \")\n            .style(StyledTextOutput.Style.Identifier)\n            .text(\"sonatypeUsername\")\n            .style(StyledTextOutput.Style.Info)\n            .text(\" or \")\n            .style(StyledTextOutput.Style.Identifier)\n            .text(\"sonatypePassword\")\n            .style(StyledTextOutput.Style.Info)\n            .text(\" are not set\")\n            .println()\n        return\n    }\n\n    apply<NexusPublishPlugin>()\n\n    configure<NexusPublishExtension> {\n        repositories {\n            sonatype {\n                /*\n                 * The default is https://oss.sonatype.org/service/local/.\n                 */\n                nexusUrl.set(uri(\"https://s01.oss.sonatype.org/service/local/\"))\n                /*\n                 * The default is https://oss.sonatype.org/content/repositories/snapshots/.\n                 */\n                snapshotRepositoryUrl.set(uri(\"https://s01.oss.sonatype.org/content/repositories/snapshots/\"))\n                username.set(property(\"sonatypeUsername\") as String)\n                password.set(property(\"sonatypePassword\") as String)\n            }\n        }\n    }\n}\n\n/**\n * Configures GitHub Packages as the publish destination.\n */\nprivate fun Project.configureGitHubPublishing() {\n    configure<PublishingExtension> {\n        repositories {\n            maven {\n                name = \"GitHub\"\n                url = uri(\"https://maven.pkg.github.com/saveourtool/diktat\")\n                credentials {\n                    username = findProperty(\"gpr.user\") as String? ?: System.getenv(\"GITHUB_ACTOR\")\n                    password = findProperty(\"gpr.key\") as String? ?: System.getenv(\"GITHUB_TOKEN\")\n                }\n            }\n        }\n    }\n}\n\n/**\n * Enables signing of the artifacts if the `signingKey` project property is set.\n *\n * Should be explicitly called after each custom `publishing {}` section.\n */\nprivate fun Project.configureSigning() {\n    setPropertyFromEnv(\"GPG_SEC\", \"signingKey\")\n    setPropertyFromEnv(\"GPG_PASSWORD\", \"signingPassword\")\n\n    if (hasProperty(\"signingKey\")) {\n        /*\n         * GitHub Actions.\n         */\n        configureSigningCommon {\n            useInMemoryPgpKeys(property(\"signingKey\") as String?, findProperty(\"signingPassword\") as String?)\n        }\n    } else if (\n        this.hasProperties(\n            \"signing.keyId\",\n            \"signing.password\",\n            \"signing.secretKeyRingFile\",\n        )\n    ) {\n        /*-\n         * Pure-Java signing mechanism via `org.bouncycastle.bcpg`.\n         *\n         * Requires an 8-digit (short form) PGP key id and a present `~/.gnupg/secring.gpg`\n         * (for gpg 2.1, run\n         * `gpg --keyring secring.gpg --export-secret-keys >~/.gnupg/secring.gpg`\n         * to generate one).\n         */\n        configureSigningCommon()\n    } else if (hasProperty(\"signing.gnupg.keyName\")) {\n        /*-\n         * Use an external `gpg` executable.\n         *\n         * On Windows, you may need to additionally specify the path to `gpg` via\n         * `signing.gnupg.executable`.\n         */\n        configureSigningCommon {\n            useGpgCmd()\n        }\n    }\n}\n\n/**\n * @param useKeys the block which configures the PGP keys. Use either\n *   [SigningExtension.useInMemoryPgpKeys], [SigningExtension.useGpgCmd], or an\n *   empty lambda.\n * @see SigningExtension.useInMemoryPgpKeys\n * @see SigningExtension.useGpgCmd\n */\nprivate fun Project.configureSigningCommon(useKeys: SigningExtension.() -> Unit = {}) {\n    apply<SigningPlugin>()\n    configure<SigningExtension> {\n        useKeys()\n        val publications = extensions.getByType<PublishingExtension>().publications\n        val publicationCount = publications.size\n        val message = \"The following $publicationCount publication(s) are getting signed: ${publications.map(Named::getName)}\"\n        val style = when (publicationCount) {\n            0 -> Failure\n            else -> Success\n        }\n        styledOut(logCategory = \"signing\").style(style).println(message)\n        sign(*publications.toTypedArray())\n    }\n    tasks.withType<PublishToMavenRepository>().configureEach {\n        // Workaround for the problem described at https://github.com/saveourtool/save-cli/pull/501#issuecomment-1439705340.\n        // We have a single Javadoc artifact shared by all platforms, hence all publications depend on signing of this artifact.\n        // This causes weird implicit dependencies, like `publishJsPublication...` depends on `signJvmPublication`.\n        dependsOn(tasks.withType<Sign>())\n    }\n}\n\n/**\n * Creates a styled text output.\n *\n * @param logCategory\n * @return [StyledTextOutput]\n */\nprivate fun Project.styledOut(logCategory: String): StyledTextOutput = serviceOf<StyledTextOutputFactory>().create(logCategory)\n\n/**\n * Determines if this project has all the given properties.\n *\n * @param propertyNames the names of the properties to locate.\n * @return `true` if this project has all the given properties, `false` otherwise.\n * @see Project.hasProperty\n */\nprivate fun Project.hasProperties(vararg propertyNames: String): Boolean = propertyNames.asSequence().all(this::hasProperty)\n\nprivate fun Project.setPropertyFromEnv(envName: String, propertyName: String) {\n    System.getenv(envName)?.let {\n        extra.set(propertyName, it)\n    }\n}\n"
  },
  {
    "path": "gradle/plugins/src/main/kotlin/com/saveourtool/diktat/buildutils/TaskNames.kt",
    "content": "/**\n * Names for common tasks\n */\n\npackage com.saveourtool.diktat.buildutils\n\n/**\n * Tasks with sources\n */\nconst val SOURCES_JAR = \"sourcesJar\"\n"
  },
  {
    "path": "gradle/plugins/src/main/kotlin/com/saveourtool/diktat/buildutils/VersioningConfiguration.kt",
    "content": "/**\n * Configuration for project versioning\n */\n\npackage com.saveourtool.diktat.buildutils\n\nimport org.ajoberstar.reckon.core.Scope\nimport org.ajoberstar.reckon.core.VersionTagParser\nimport org.ajoberstar.reckon.gradle.ReckonExtension\nimport org.ajoberstar.reckon.gradle.ReckonPlugin\nimport org.eclipse.jgit.api.Git\nimport org.eclipse.jgit.internal.storage.file.FileRepository\nimport org.eclipse.jgit.storage.file.FileRepositoryBuilder\nimport org.gradle.api.Project\nimport org.gradle.kotlin.dsl.apply\nimport org.gradle.kotlin.dsl.configure\nimport java.util.Optional\n\n/**\n * Configures reckon plugin for [this] project, should be applied for root project only\n */\nfun Project.configureVersioning() {\n    apply<ReckonPlugin>()\n\n    // should be provided in the gradle.properties\n    configure<ReckonExtension> {\n        setDefaultInferredScope(Scope.MINOR.name)\n        if (findProperty(\"reckon.stage\")?.toString() == \"snapshot\") {\n            snapshots()\n            // skip -rc candidates tags\n            setTagParser { tagName ->\n                if (tagName.contains(\"-rc.[0-9]+\".toRegex())) {\n                    Optional.empty()\n                } else {\n                    VersionTagParser.getDefault().parse(tagName)\n                }\n            }\n        } else {\n            stages(\"rc\", \"final\")\n        }\n        setScopeCalc(calcScopeFromProp())\n        setStageCalc(calcStageFromProp())\n    }\n\n    val status = FileRepositoryBuilder()\n        .findGitDir(project.rootDir)\n        .setup()\n        .let(::FileRepository)\n        .let(::Git)\n        .status()\n        .call()\n\n    if (!status.isClean) {\n        logger.warn(\"git tree is not clean; \" +\n                \"Untracked files: ${status.untracked}, uncommitted changes: ${status.uncommittedChanges}\"\n        )\n    }\n}\n"
  },
  {
    "path": "gradle/plugins/src/main/kotlin/com/saveourtool/diktat/buildutils/code-quality-convention.gradle.kts",
    "content": "package com.saveourtool.diktat.buildutils\n\n// FixMe: remove after 2.0.0\nrun {\n    @Suppress(\"RUN_IN_SCRIPT\", \"AVOID_NULL_CHECKS\")\n    plugins {\n        id(\"com.saveourtool.diktat.buildutils.detekt-convention-configuration\")\n        id(\"com.saveourtool.diktat.buildutils.diktat-convention-configuration\")\n    }\n}\n"
  },
  {
    "path": "gradle/plugins/src/main/kotlin/com/saveourtool/diktat/buildutils/detekt-convention-configuration.gradle.kts",
    "content": "package com.saveourtool.diktat.buildutils\n\nimport io.gitlab.arturbosch.detekt.Detekt\nimport io.gitlab.arturbosch.detekt.report.ReportMergeTask\n\nplugins {\n    id(\"io.gitlab.arturbosch.detekt\")\n}\n\ndetekt {\n    config.setFrom(rootProject.files(\"detekt-config.yml\"))\n    basePath = rootDir.canonicalPath\n    buildUponDefaultConfig = true\n}\n\n@Suppress(\"RUN_IN_SCRIPT\")\nif (path == rootProject.path) {\n    tasks.register(\"detektAll\") {\n        allprojects {\n            this@register.dependsOn(tasks.withType<Detekt>())\n        }\n    }\n\n    tasks.register(\"mergeDetektReports\", ReportMergeTask::class) {\n        output.set(layout.buildDirectory.file(\"detekt-sarif-reports/detekt-merged.sarif\").get().asFile)\n    }\n}\n\n@Suppress(\"GENERIC_VARIABLE_WRONG_DECLARATION\")\nval reportMerge: TaskProvider<ReportMergeTask> = rootProject.tasks.named<ReportMergeTask>(\"mergeDetektReports\") {\n    input.from(\n        tasks.withType<Detekt>().map { it.sarifReportFile }\n    )\n    shouldRunAfter(tasks.withType<Detekt>())\n}\ntasks.withType<Detekt>().configureEach {\n    reports.sarif.required.set(true)\n    finalizedBy(reportMerge)\n}\n"
  },
  {
    "path": "gradle/plugins/src/main/kotlin/com/saveourtool/diktat/buildutils/diktat-convention-configuration.gradle.kts",
    "content": "package com.saveourtool.diktat.buildutils\n\nplugins {\n    id(\"com.saveourtool.diktat\")\n}\n\ndiktat {\n    diktatConfigFile = rootProject.file(\"diktat-analysis.yml\")\n    githubActions = findProperty(\"diktat.githubActions\")?.toString()?.toBoolean() ?: false\n    inputs {\n        // using `Project#path` here, because it must be unique in gradle's project hierarchy\n        if (path == rootProject.path) {\n            include(\"gradle/plugins/src/**/*.kt\", \"*.kts\", \"gradle/plugins/**/*.kts\")\n            exclude(\"gradle/plugins/build/**\")\n        } else {\n            include(\"src/**/*.kt\", \"**/*.kts\")\n            exclude(\n                \"src/test/**/*.kt\",\n                \"src/test/**/*.kts\",\n                \"src/*Test/**/*.kt\",\n                \"build/**/*.kts\",\n            )\n        }\n    }\n}\n"
  },
  {
    "path": "gradle/plugins/src/main/kotlin/com/saveourtool/diktat/buildutils/git-hook-configuration.gradle.kts",
    "content": "package com.saveourtool.diktat.buildutils\n\n/**\n * Task of type [Copy] that install git hooks from directory in repo to .git directory\n */\nval installGitHooksTask = tasks.register(\"installGitHooks\", Copy::class) {\n    from(file(\"$rootDir/.git-hooks\"))\n    into(file(\"$rootDir/.git/hooks\"))\n}\n\n// add git hooks installation to build by adding it as a dependency for some common task\nrun {\n    tasks.findByName(\"build\")?.dependsOn(installGitHooksTask)\n}\n"
  },
  {
    "path": "gradle/plugins/src/main/kotlin/com/saveourtool/diktat/buildutils/kotlin-jvm-configuration.gradle.kts",
    "content": "package com.saveourtool.diktat.buildutils\n\nimport org.gradle.api.tasks.testing.Test\n\nplugins {\n    kotlin(\"jvm\")\n}\n\njava {\n    toolchain {\n        languageVersion.set(JavaLanguageVersion.of(Versions.jdk))\n    }\n}\n\nkotlin {\n    compilerOptions {\n        optIn.add(\"kotlin.RequiresOptIn\")\n    }\n\n    jvmToolchain {\n        languageVersion.set(JavaLanguageVersion.of(Versions.jdk))\n    }\n}\n\ntasks.register<Jar>(SOURCES_JAR) {\n    archiveClassifier.set(\"sources\")\n    from(kotlin.sourceSets.main.map { it.kotlin })\n}\n\nconfigureJacoco()\ntasks.withType<Test> {\n    useJUnitPlatform()\n}\n"
  },
  {
    "path": "gradle/plugins/src/main/kotlin/com/saveourtool/diktat/buildutils/publishing-configuration.gradle.kts",
    "content": "package com.saveourtool.diktat.buildutils\n\nimport org.gradle.kotlin.dsl.`maven-publish`\n\nplugins {\n    `maven-publish`\n}\n\nconfigurePublishing()\n"
  },
  {
    "path": "gradle/plugins/src/main/kotlin/com/saveourtool/diktat/buildutils/publishing-default-configuration.gradle.kts",
    "content": "package com.saveourtool.diktat.buildutils\n\nimport org.gradle.api.publish.maven.MavenPublication\nimport org.gradle.kotlin.dsl.create\nimport org.gradle.kotlin.dsl.get\n\nplugins {\n    `maven-publish`\n}\n\npublishing {\n    publications {\n        create<MavenPublication>(\"maven\") {\n            from(components[\"java\"])\n        }\n    }\n}\n\nconfigurePublications()\nconfigurePublishing()\n"
  },
  {
    "path": "gradle/plugins/src/main/kotlin/com/saveourtool/diktat/buildutils/versioning-configuration.gradle.kts",
    "content": "package com.saveourtool.diktat.buildutils\n\nconfigureVersioning()\n"
  },
  {
    "path": "gradle/wrapper/gradle-wrapper.properties",
    "content": "distributionBase=GRADLE_USER_HOME\ndistributionPath=wrapper/dists\ndistributionUrl=https\\://services.gradle.org/distributions/gradle-8.11.1-bin.zip\nnetworkTimeout=10000\nvalidateDistributionUrl=true\nzipStoreBase=GRADLE_USER_HOME\nzipStorePath=wrapper/dists\n"
  },
  {
    "path": "gradle.properties",
    "content": "group=com.saveourtool.diktat\n\n# gradle performance\norg.gradle.jvmargs=-Xmx3g -XX:MaxMetaspaceSize=512m\norg.gradle.parallel=true\norg.gradle.vfs.watch=true\n\n# See <https://docs.gradle.com/enterprise/gradle-plugin/>\n#\n# If this is enabled, the Gradle Enterprise plug-in will be conflicting with\n# the Test Retry plug-in (org.gradle.test-retry,\n# <https://github.com/gradle/test-retry-gradle-plugin>).\nsystemProp.gradle.enterprise.testretry.enabled=false\n"
  },
  {
    "path": "gradlew",
    "content": "#!/bin/sh\n\n#\n# Copyright © 2015-2021 the original authors.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#      https://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n#\n# SPDX-License-Identifier: Apache-2.0\n#\n\n##############################################################################\n#\n#   Gradle start up script for POSIX generated by Gradle.\n#\n#   Important for running:\n#\n#   (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is\n#       noncompliant, but you have some other compliant shell such as ksh or\n#       bash, then to run this script, type that shell name before the whole\n#       command line, like:\n#\n#           ksh Gradle\n#\n#       Busybox and similar reduced shells will NOT work, because this script\n#       requires all of these POSIX shell features:\n#         * functions;\n#         * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,\n#           «${var#prefix}», «${var%suffix}», and «$( cmd )»;\n#         * compound commands having a testable exit status, especially «case»;\n#         * various built-in commands including «command», «set», and «ulimit».\n#\n#   Important for patching:\n#\n#   (2) This script targets any POSIX shell, so it avoids extensions provided\n#       by Bash, Ksh, etc; in particular arrays are avoided.\n#\n#       The \"traditional\" practice of packing multiple parameters into a\n#       space-separated string is a well documented source of bugs and security\n#       problems, so this is (mostly) avoided, by progressively accumulating\n#       options in \"$@\", and eventually passing that to Java.\n#\n#       Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,\n#       and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;\n#       see the in-line comments for details.\n#\n#       There are tweaks for specific operating systems such as AIX, CygWin,\n#       Darwin, MinGW, and NonStop.\n#\n#   (3) This script is generated from the Groovy template\n#       https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt\n#       within the Gradle project.\n#\n#       You can find Gradle at https://github.com/gradle/gradle/.\n#\n##############################################################################\n\n# Attempt to set APP_HOME\n\n# Resolve links: $0 may be a link\napp_path=$0\n\n# Need this for daisy-chained symlinks.\nwhile\n    APP_HOME=${app_path%\"${app_path##*/}\"}  # leaves a trailing /; empty if no leading path\n    [ -h \"$app_path\" ]\ndo\n    ls=$( ls -ld \"$app_path\" )\n    link=${ls#*' -> '}\n    case $link in             #(\n      /*)   app_path=$link ;; #(\n      *)    app_path=$APP_HOME$link ;;\n    esac\ndone\n\n# This is normally unused\n# shellcheck disable=SC2034\nAPP_BASE_NAME=${0##*/}\n# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)\nAPP_HOME=$( cd -P \"${APP_HOME:-./}\" > /dev/null && printf '%s\n' \"$PWD\" ) || exit\n\n# Use the maximum available, or set MAX_FD != -1 to use that value.\nMAX_FD=maximum\n\nwarn () {\n    echo \"$*\"\n} >&2\n\ndie () {\n    echo\n    echo \"$*\"\n    echo\n    exit 1\n} >&2\n\n# OS specific support (must be 'true' or 'false').\ncygwin=false\nmsys=false\ndarwin=false\nnonstop=false\ncase \"$( uname )\" in                #(\n  CYGWIN* )         cygwin=true  ;; #(\n  Darwin* )         darwin=true  ;; #(\n  MSYS* | MINGW* )  msys=true    ;; #(\n  NONSTOP* )        nonstop=true ;;\nesac\n\nCLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar\n\n\n# Determine the Java command to use to start the JVM.\nif [ -n \"$JAVA_HOME\" ] ; then\n    if [ -x \"$JAVA_HOME/jre/sh/java\" ] ; then\n        # IBM's JDK on AIX uses strange locations for the executables\n        JAVACMD=$JAVA_HOME/jre/sh/java\n    else\n        JAVACMD=$JAVA_HOME/bin/java\n    fi\n    if [ ! -x \"$JAVACMD\" ] ; then\n        die \"ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME\n\nPlease set the JAVA_HOME variable in your environment to match the\nlocation of your Java installation.\"\n    fi\nelse\n    JAVACMD=java\n    if ! command -v java >/dev/null 2>&1\n    then\n        die \"ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.\n\nPlease set the JAVA_HOME variable in your environment to match the\nlocation of your Java installation.\"\n    fi\nfi\n\n# Increase the maximum file descriptors if we can.\nif ! \"$cygwin\" && ! \"$darwin\" && ! \"$nonstop\" ; then\n    case $MAX_FD in #(\n      max*)\n        # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.\n        # shellcheck disable=SC2039,SC3045\n        MAX_FD=$( ulimit -H -n ) ||\n            warn \"Could not query maximum file descriptor limit\"\n    esac\n    case $MAX_FD in  #(\n      '' | soft) :;; #(\n      *)\n        # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.\n        # shellcheck disable=SC2039,SC3045\n        ulimit -n \"$MAX_FD\" ||\n            warn \"Could not set maximum file descriptor limit to $MAX_FD\"\n    esac\nfi\n\n# Collect all arguments for the java command, stacking in reverse order:\n#   * args from the command line\n#   * the main class name\n#   * -classpath\n#   * -D...appname settings\n#   * --module-path (only if needed)\n#   * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.\n\n# For Cygwin or MSYS, switch paths to Windows format before running java\nif \"$cygwin\" || \"$msys\" ; then\n    APP_HOME=$( cygpath --path --mixed \"$APP_HOME\" )\n    CLASSPATH=$( cygpath --path --mixed \"$CLASSPATH\" )\n\n    JAVACMD=$( cygpath --unix \"$JAVACMD\" )\n\n    # Now convert the arguments - kludge to limit ourselves to /bin/sh\n    for arg do\n        if\n            case $arg in                                #(\n              -*)   false ;;                            # don't mess with options #(\n              /?*)  t=${arg#/} t=/${t%%/*}              # looks like a POSIX filepath\n                    [ -e \"$t\" ] ;;                      #(\n              *)    false ;;\n            esac\n        then\n            arg=$( cygpath --path --ignore --mixed \"$arg\" )\n        fi\n        # Roll the args list around exactly as many times as the number of\n        # args, so each arg winds up back in the position where it started, but\n        # possibly modified.\n        #\n        # NB: a `for` loop captures its iteration list before it begins, so\n        # changing the positional parameters here affects neither the number of\n        # iterations, nor the values presented in `arg`.\n        shift                   # remove old arg\n        set -- \"$@\" \"$arg\"      # push replacement arg\n    done\nfi\n\n\n# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.\nDEFAULT_JVM_OPTS='\"-Xmx64m\" \"-Xms64m\"'\n\n# Collect all arguments for the java command:\n#   * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,\n#     and any embedded shellness will be escaped.\n#   * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be\n#     treated as '${Hostname}' itself on the command line.\n\nset -- \\\n        \"-Dorg.gradle.appname=$APP_BASE_NAME\" \\\n        -classpath \"$CLASSPATH\" \\\n        org.gradle.wrapper.GradleWrapperMain \\\n        \"$@\"\n\n# Stop when \"xargs\" is not available.\nif ! command -v xargs >/dev/null 2>&1\nthen\n    die \"xargs is not available\"\nfi\n\n# Use \"xargs\" to parse quoted args.\n#\n# With -n1 it outputs one arg per line, with the quotes and backslashes removed.\n#\n# In Bash we could simply go:\n#\n#   readarray ARGS < <( xargs -n1 <<<\"$var\" ) &&\n#   set -- \"${ARGS[@]}\" \"$@\"\n#\n# but POSIX shell has neither arrays nor command substitution, so instead we\n# post-process each arg (as a line of input to sed) to backslash-escape any\n# character that might be a shell metacharacter, then use eval to reverse\n# that process (while maintaining the separation between arguments), and wrap\n# the whole thing up as a single \"set\" statement.\n#\n# This will of course break if any of these variables contains a newline or\n# an unmatched quote.\n#\n\neval \"set -- $(\n        printf '%s\\n' \"$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS\" |\n        xargs -n1 |\n        sed ' s~[^-[:alnum:]+,./:=@_]~\\\\&~g; ' |\n        tr '\\n' ' '\n    )\" '\"$@\"'\n\nexec \"$JAVACMD\" \"$@\"\n"
  },
  {
    "path": "gradlew.bat",
    "content": "@rem\r\n@rem Copyright 2015 the original author or authors.\r\n@rem\r\n@rem Licensed under the Apache License, Version 2.0 (the \"License\");\r\n@rem you may not use this file except in compliance with the License.\r\n@rem You may obtain a copy of the License at\r\n@rem\r\n@rem      https://www.apache.org/licenses/LICENSE-2.0\r\n@rem\r\n@rem Unless required by applicable law or agreed to in writing, software\r\n@rem distributed under the License is distributed on an \"AS IS\" BASIS,\r\n@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r\n@rem See the License for the specific language governing permissions and\r\n@rem limitations under the License.\r\n@rem\r\n@rem SPDX-License-Identifier: Apache-2.0\r\n@rem\r\n\r\n@if \"%DEBUG%\"==\"\" @echo off\r\n@rem ##########################################################################\r\n@rem\r\n@rem  Gradle startup script for Windows\r\n@rem\r\n@rem ##########################################################################\r\n\r\n@rem Set local scope for the variables with windows NT shell\r\nif \"%OS%\"==\"Windows_NT\" setlocal\r\n\r\nset DIRNAME=%~dp0\r\nif \"%DIRNAME%\"==\"\" set DIRNAME=.\r\n@rem This is normally unused\r\nset APP_BASE_NAME=%~n0\r\nset APP_HOME=%DIRNAME%\r\n\r\n@rem Resolve any \".\" and \"..\" in APP_HOME to make it shorter.\r\nfor %%i in (\"%APP_HOME%\") do set APP_HOME=%%~fi\r\n\r\n@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.\r\nset DEFAULT_JVM_OPTS=\"-Xmx64m\" \"-Xms64m\"\r\n\r\n@rem Find java.exe\r\nif defined JAVA_HOME goto findJavaFromJavaHome\r\n\r\nset JAVA_EXE=java.exe\r\n%JAVA_EXE% -version >NUL 2>&1\r\nif %ERRORLEVEL% equ 0 goto execute\r\n\r\necho. 1>&2\r\necho ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2\r\necho. 1>&2\r\necho Please set the JAVA_HOME variable in your environment to match the 1>&2\r\necho location of your Java installation. 1>&2\r\n\r\ngoto fail\r\n\r\n:findJavaFromJavaHome\r\nset JAVA_HOME=%JAVA_HOME:\"=%\r\nset JAVA_EXE=%JAVA_HOME%/bin/java.exe\r\n\r\nif exist \"%JAVA_EXE%\" goto execute\r\n\r\necho. 1>&2\r\necho ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2\r\necho. 1>&2\r\necho Please set the JAVA_HOME variable in your environment to match the 1>&2\r\necho location of your Java installation. 1>&2\r\n\r\ngoto fail\r\n\r\n:execute\r\n@rem Setup the command line\r\n\r\nset CLASSPATH=%APP_HOME%\\gradle\\wrapper\\gradle-wrapper.jar\r\n\r\n\r\n@rem Execute Gradle\r\n\"%JAVA_EXE%\" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% \"-Dorg.gradle.appname=%APP_BASE_NAME%\" -classpath \"%CLASSPATH%\" org.gradle.wrapper.GradleWrapperMain %*\r\n\r\n:end\r\n@rem End local scope for the variables with windows NT shell\r\nif %ERRORLEVEL% equ 0 goto mainEnd\r\n\r\n:fail\r\nrem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of\r\nrem the _cmd.exe /c_ return code!\r\nset EXIT_CODE=%ERRORLEVEL%\r\nif %EXIT_CODE% equ 0 set EXIT_CODE=1\r\nif not \"\"==\"%GRADLE_EXIT_CONSOLE%\" exit %EXIT_CODE%\r\nexit /b %EXIT_CODE%\r\n\r\n:mainEnd\r\nif \"%OS%\"==\"Windows_NT\" endlocal\r\n\r\n:omega\r\n"
  },
  {
    "path": "info/README.md",
    "content": "# UPDATE THE MAIN [README.md](../README.md)\n\n#### To update the codestyle text in the main [README.md](../README.md):\n\n* You **NEED TO CHANGE** the content of the file `guide-chapter-<N>.md`, contained in `info/guide`, the corresponding section of the rules that you changed / added.\n\n* ```console\n  $ cd info/\n  $ ./gradlew :generateFullDoc\n  $ ./gradlew :generateAvailableRules\n  ```\n\n#### You **DO NOT NEED TO CHANGE** the content of the [`diktat-coding-convention.md`](guide/diktat-coding-convention.md) file.\n"
  },
  {
    "path": "info/available-rules.md",
    "content": "| Chap | Standard | Rule name                                 | Description                                                                                                                                                                                                                                                                                                                                                 | Fix | Config                                                                                                                                                                                                                     | FixMe                                                                                                                                                                                                                                 |\n|------|----------|-------------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-----|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|\n| 1    | 1.1.1    | CONFUSING_IDENTIFIER_NAMING               | Check: warns if the identifier has an inappropriate name (see table of [rule 1.2 part 6](guide/diktat-coding-convention.md#-111-identifiers-naming-conventions)).                                                                                                                                                                                           | no  | no                                                                                                                                                                                                                         | no                                                                                                                                                                                                                                    |\n| 1    | 1.1.1    | BACKTICKS_PROHIBITED                      | Check: warns if backticks (``) are used in the identifier name, except in the case when it is a test method (marked with `@Test` annotation).                                                                                                                                                                                                               | no  | no                                                                                                                                                                                                                         | -                                                                                                                                                                                                                                     |\n| 1    | 1.1.1    | VARIABLE_NAME_INCORRECT                   | Check: warns if a variable name consists of only a single character; the only exceptions are industry-standard fixed names, such as {`i`, `j`}.<br>Fix: No fix is available, since it is the responsibility of a human to choose a meaningful identifier name.                                                                                              | no  | no                                                                                                                                                                                                                         | Recursively update usages of this class in the projectMake exceptions configurable.                                                                                                                                                   |\n| 1    | 1.1.1    | EXCEPTION_SUFFIX                          | Check: warns if a class that extends any `Exception` class does not have an \"Exception\" suffix.<br>Fix: adding the \"Exception\" suffix to the class name.                                                                                                                                                                                                    | yes | no                                                                                                                                                                                                                         | Need to add tests for this.                                                                                                                                                                                                           |\n| 1    | 1.1.1    | IDENTIFIER_LENGTH                         | Check: identifier length should be in the [2,64] range , except for industry-standard names, such as {`i`, `j`} and 'e' for catching exceptions.<br>Fix: Fix: no fix is available, since only a human can choose a meaningful identifier name, depending on the context.                                                                                    | no  | no                                                                                                                                                                                                                         | May be make this rule configurable (length)                                                                                                                                                                                           |\n| 1    | 1.1.1    | FILE_NAME_INCORRECT                       | Check: warns if a file name does not have a `.kt`/`.kts` extension.<br>Fix: no                                                                                                                                                                                                                                                                              | no  | no                                                                                                                                                                                                                         | Extensions should be configurable; it can be autofixed.                                                                                                                                                                               |\n| 1    | 1.1.1    | GENERIC_NAME                              | Check: warns if the name of a  [_generic type parameter_](https://kotlinlang.org/docs/generics.html) (e.g. `T`) consists of more than a single capital letter. The capital letter can be followed by numbers, though (e.g. `T12`).<br>Fix:                                                                                                                  | yes | no                                                                                                                                                                                                                         | Recursively update usages of this identifier in the project.                                                                                                                                                                          |\n| 1    | 1.1.1    | VARIABLE_HAS_PREFIX                       | Check: warns if the name of a variable has a [Hungarian notation](https://en.wikipedia.org/wiki/Hungarian_notation) specific prefix (like `mVariable` or `M_VARIABLE`), which is considered a bad code style (_Android_ is the only exception).<br>Fix: none is available, as only a human can choose a meaningful name, depending on a particular context. | no  | no                                                                                                                                                                                                                         |                                                                                                                                                                                                                                       |\n| 1    | 1.2.1    | PACKAGE_NAME_MISSING                      | Check: warns if a package declaration is missing in the file.<br>Fix: automatically adds a package directive with the name that starts from the domain name (example - com.huawei) and contains the real directory.                                                                                                                                         | yes | no                                                                                                                                                                                                                         | Recursively fix all imports in the project.<br>Fix the directory where the code is stored.<br>Make this check isolated from the domain name addition.                                                                                 |\n| 1    | 1.2.1    | PACKAGE_NAME_INCORRECT_CASE               | Check: warns if a package name is incorrect (non-lower) case.<br>Fix: automatically update the case in package name.                                                                                                                                                                                                                                        | yes | no                                                                                                                                                                                                                         | Recursively update all imports in the project.                                                                                                                                                                                        |\n| 1    | 1.2.1    | PACKAGE_NAME_INCORRECT_PREFIX             | Check: warns if a package name does not start with the company's domain.<br>Fix: automatically update the prefix in the package name.                                                                                                                                                                                                                       | yes | no                                                                                                                                                                                                                         | Fix the directory where the code is stored.<br>Recursively update all imports in the project.                                                                                                                                         |\n| 1    | 1.2.1    | PACKAGE_NAME_INCORRECT_SYMBOLS            | Check: warns if a package name has incorrect symbols, such as underscore or non-ASCII letters/digits. Exception: underscores that are used for differentiating of keywords in a name.<br>Fix: no fix currently available; will be suggested later.                                                                                                          | no  | no                                                                                                                                                                                                                         | Add autofix for at least converting underscore to a dot or replacing itFix the directory where the code is stored. Cover autofix with tests.                                                                                          |\n| 1    | 1.2.1    | PACKAGE_NAME_INCORRECT_PATH               | Check: warns if the path for a file does not match with a package name.<br>Fix: replacing the incorrect package name with the name constructed from a path to the file.                                                                                                                                                                                     | yes | no                                                                                                                                                                                                                         | Make this check isolated from domain name creation. Recursively update all imports in the project. Fix the directory where the code is stored. Add a test mechanism to test checker.                                                  |\n| 1    | 1.2.1    | INCORRECT_PACKAGE_SEPARATOR               | Check: warns if the underscore is incorrectly used in package naming to split name parts.<br>Fix: fixing all nodes in AST and the package name to remove all underscores.                                                                                                                                                                                   | no  | no                                                                                                                                                                                                                         | Recursively update usages of this class in the project.                                                                                                                                                                               |\n| 1    | 1.3.1    | CLASS_NAME_INCORRECT                      | Check: warns if the Class/Enum/Interface name does not match the Pascal case (\"([A-Z][a-z0-9]+)+\").<br>Fix: fixing the case. If it is some fixed case (like Snake or Camel) - with word saving; if not - will restore PascalCase as is.                                                                                                                     | yes | no                                                                                                                                                                                                                         | Recursively update usages of this class in the projectCheck and find the better way of converting the identifier to PascalCaseNeed to add checks using natural language processing and check that the class name contains only nouns. |\n| 1    | 1.3.1    | OBJECT_NAME_INCORRECT                     | Check: warns if the object does not match the Pascal case (\"([A-Z][a-z0-9]+)+\").<br>Fix: fixing the case in the same way as for the classes.                                                                                                                                                                                                                | yes | no                                                                                                                                                                                                                         | Recursively update usages of this class in the project.                                                                                                                                                                               |\n| 1    | 1.3.1    | ENUM_VALUE                                | Check: verifies if the enum value is in UPPER_SNAKE_CASE or in PascalCase depending on the configuration. UPPER_SNAKE_CASE is the default configuration, but can be changed by 'enumStyle' config.<br>Fix: automatically converting the enum case to a properly selected case                                                                               | yes | enumStyle: snakeCase, pascalCase                                                                                                                                                                                           | Recursively update usages of this identifier in the project.                                                                                                                                                                          |\n| 1    | 1.3.1    | TYPEALIAS_NAME_INCORRECT_CASE             | Check: typealias name should be in pascalCase.<br>Fix:                                                                                                                                                                                                                                                                                                      | yes | no                                                                                                                                                                                                                         | Recursively update usages of this typealias in the project.                                                                                                                                                                           |\n| 1    | 1.4.1    | FUNCTION_NAME_INCORRECT_CASE              | Check: function/method name should be in lowerCamelCase.<br>Fix:                                                                                                                                                                                                                                                                                            | yes | no                                                                                                                                                                                                                         | Recursively update usages of this function in the project.                                                                                                                                                                            |\n| 1    | 1.5.1    | CONSTANT_UPPERCASE                        | Check: warns if CONSTANT (treated as const val from companion object or class level) is not in UPPER_SNAKE_CASE.<br>Fix: name is changed to UPPER_SNAKE_CASE.                                                                                                                                                                                               | yes | no                                                                                                                                                                                                                         | Recursively update usages of this identifier in the project.                                                                                                                                                                          |\n| 1    | 1.6.1    | VARIABLE_NAME_INCORRECT_FORMAT            | Check: warns if the name of a variable is not in lowerCamelCase or contains non-ASCII letters.<br>Fix: fixing the case format to lowerCamelCase.                                                                                                                                                                                                            | yes | no                                                                                                                                                                                                                         | -                                                                                                                                                                                                                                     |\n| 1    | 1.6.2    | FUNCTION_BOOLEAN_PREFIX                   | Check: functions/methods that return boolean should have a special prefix, such as \"is/should/etc.\"<br>Fix:                                                                                                                                                                                                                                                 | yes | no                                                                                                                                                                                                                         | Recursively update usages of this function in the project. Aggressive fix - what if the new name will not be valid?                                                                                                                   |\n| 2    | 2.1.1    | MISSING_KDOC_TOP_LEVEL                    | Check: warns at a file level internal or public class or if the function has a missing KDoc.<br>Fix: no                                                                                                                                                                                                                                                     | no  | no                                                                                                                                                                                                                         | Support extension for setters/getters. Support extension for method \"override\".                                                                                                                                                       |\n| 2    | 2.1.1    | KDOC_EXTRA_PROPERTY                       | Check: warn if there is a property in KDoc that is not present in the class.                                                                                                                                                                                                                                                                                | no  | no                                                                                                                                                                                                                         | -                                                                                                                                                                                                                                     |\n| 2    | 2.1.1    | KDOC_DUPLICATE_PROPERTY                   | Check: warn if there's a property in KDoc which is already present.                                                                                                                                                                                                                                                                                         | no  | no                                                                                                                                                                                                                         | -                                                                                                                                                                                                                                     |\n| 2    | 2.1.1    | MISSING_KDOC_CLASS_ELEMENTS               | Check: warns if accessible internal elements (protected, public, internal) in a class are not documented.<br>Fix: no                                                                                                                                                                                                                                        | no  | no                                                                                                                                                                                                                         | Maybe exception cases for setters and getters are needed; no sense in adding KDoc to them.                                                                                                                                            |\n| 2    | 2.1.1    | MISSING_KDOC_ON_FUNCTION                  | Check: warns if accessible function doesn't have KDoc.<br>Fix: adds KDoc template if it is not empty.                                                                                                                                                                                                                                                       | yes | no                                                                                                                                                                                                                         |                                                                                                                                                                                                                                       |\n| 2    | 2.1.1    | KDOC_NO_CONSTRUCTOR_PROPERTY              | Check: warns if there is no property tag inside KDoc before the constructor.                                                                                                                                                                                                                                                                                | yes | isParamTagsForParameters, isParamTagsForPrivateProperties, isParamTagsForGenericTypes                                                                                                                                      |                                                                                                                                                                                                                                       |\n| 2    | 2.1.1    | KDOC_NO_CLASS_BODY_PROPERTIES_IN_HEADER   | Check: warns if the property is declared in a class body but documented with a property tag inside KDoc before the constructor.                                                                                                                                                                                                                             | yes | no                                                                                                                                                                                                                         |                                                                                                                                                                                                                                       |\n| 2    | 2.1.1    | KDOC_NO_CONSTRUCTOR_PROPERTY_WITH_COMMENT | Check: warns if there is a comment before the property in the constructor.                                                                                                                                                                                                                                                                                  | yes | no                                                                                                                                                                                                                         |                                                                                                                                                                                                                                       |\n| 2    | 2.1.1    | COMMENTED_BY_KDOC                         | Check: warns if there is a kdoc comment in the code block.                                                                                                                                                                                                                                                                                                  | yes | no                                                                                                                                                                                                                         | replace \"/**\" to \"/*\"                                                                                                                                                                                                                 |\n| 2    | 2.1.2    | KDOC_WITHOUT_PARAM_TAG                    | Check: warns if an accessible method has parameters and they are not documented in KDoc.<br>Fix: If accessible method has no KDoc, the KDoc template is added.                                                                                                                                                                                              | yes | no                                                                                                                                                                                                                         | Should also make a separate fix, even if there is already some Kdoc in place.                                                                                                                                                         |\n| 2    | 2.1.2    | KDOC_WITHOUT_RETURN_TAG                   | Check: warns if the accessible method has an explicit return type. Then it is not documented in KDoc.<br>Fix: If the accessible method has no KDoc, the KDoc template is added.                                                                                                                                                                             | yes | no                                                                                                                                                                                                                         | Should also make separate fix, even if there is already some Kdoc in place.                                                                                                                                                           |\n| 2    | 2.1.2    | KDOC_WITHOUT_THROWS_TAG                   | Check: warns if the accessible method has the throw keyword and it is not documented in KDoc.<br>Fix: if the accessible method has no KDoc, KDoc template is added.                                                                                                                                                                                         | yes | no                                                                                                                                                                                                                         | Should also make separate fix, even if there is already some Kdoc in place.                                                                                                                                                           |\n| 2    | 2.1.3    | KDOC_EMPTY_KDOC                           | Check: warns if the KDoc is empty.<br>Fix: no                                                                                                                                                                                                                                                                                                               | no  | no                                                                                                                                                                                                                         |                                                                                                                                                                                                                                       |\n| 2    | 2.1.3    | KDOC_WRONG_SPACES_AFTER_TAG               | Check: warns if there is more than one space after the KDoc tag.<br>Fix: removes redundant spaces.                                                                                                                                                                                                                                                          | yes | no                                                                                                                                                                                                                         |                                                                                                                                                                                                                                       |\n| 2    | 2.1.3    | KDOC_WRONG_TAGS_ORDER                     | Check: warns if the basic KDoc tags are not ordered properly.<br>Fix: reorders tags (`@receiver`, `@param`, `@property`, `@return`, `@throws` or `@exception`, `@constructor`).                                                                                                                                                                             | yes | no                                                                                                                                                                                                                         | Ensure basic tags are at the end of KDoc.                                                                                                                                                                                             |\n| 2    | 2.1.3    | KDOC_NEWLINES_BEFORE_BASIC_TAGS           | Check: warns if the block of tags (@param, @return, @throws) is not separated from the previous part of KDoc by exactly one empty line.<br>Fix: adds an empty line or removes a redundant one.                                                                                                                                                              | yes | no                                                                                                                                                                                                                         |                                                                                                                                                                                                                                       |\n| 2    | 2.1.3    | KDOC_NO_NEWLINES_BETWEEN_BASIC_TAGS       | Check: if there is a newline of an empty KDoc line (with a leading asterisk) between `@param`, `@return`, `@throws` tags.<br>Fix: removes the line.                                                                                                                                                                                                         | yes | no                                                                                                                                                                                                                         |                                                                                                                                                                                                                                       |\n| 2    | 2.1.3    | KDOC_NO_NEWLINE_AFTER_SPECIAL_TAGS        | Check: warns if special tags `@apiNote`, `@implNote`, `@implSpec` don't have exactly one empty line after.<br>Fix: removes redundant lines or adds one.                                                                                                                                                                                                     | yes | no                                                                                                                                                                                                                         | Handle empty lines without a leading asterisk.                                                                                                                                                                                        |\n| 2    | 2.1.3    | KDOC_NO_DEPRECATED_TAG                    | Check: warns if `@deprecated` is used in KDoc.<br>Fix: adds `@Deprecated` annotation with a message; removes the tag.                                                                                                                                                                                                                                       | yes | no                                                                                                                                                                                                                         | The `replaceWith` field in the annotation can also be filled with a meaningful value.                                                                                                                                                 |\n| 2    | 2.2.1    | KDOC_NO_EMPTY_TAGS                        | Check: warns if the KDoc tags have an empty content.                                                                                                                                                                                                                                                                                                        | no  | no                                                                                                                                                                                                                         |                                                                                                                                                                                                                                       |\n| 2    | 2.2.1    | KDOC_CONTAINS_DATE_OR_AUTHOR              | Check: warns if the KDoc header contains the `@author` tag.<br>Also warns if the `@since` tag is present but contains anything but version (e.g.: a date).                                                                                                                                                                                                  | no  | no                                                                                                                                                                                                                         | Detect the author by other patterns (e.g. 'created by' etc.)                                                                                                                                                                          |\n| 2    | 2.2.1    | HEADER_WRONG_FORMAT                       | Checks: warns if there is no newline after the KDoc header.<br>Fix: adds a newline                                                                                                                                                                                                                                                                          | yes | no                                                                                                                                                                                                                         | Check if the header is on the very top of the file. It is hard to determine when it is not.                                                                                                                                           |\n| 2    | 2.2.1    | HEADER_MISSING_OR_WRONG_COPYRIGHT         | Checks: copyright exists on top of the file and is properly formatted (as a block comment).<br>Fix: adds copyright if it is missing and required.                                                                                                                                                                                                           | yes | isCopyrightMandatory, copyrightText (sets the copyright pattern for your project, you also can use `;@currYear;` the key word in your text in aim to indicate the current year, instead of explicitly specifying).         |                                                                                                                                                                                                                                       |\n| 2    | 2.2.1    | WRONG_COPYRIGHT_YEAR                      | Checks: copyright has a valid year.<br>Fix: makes the year valid.                                                                                                                                                                                                                                                                                           | yes | no                                                                                                                                                                                                                         | -                                                                                                                                                                                                                                     |\n| 2    | 2.2.1    | HEADER_MISSING_IN_NON_SINGLE_CLASS_FILE   | Check: warns if a file with zero or >1 classes doesn't have a KDoc header.                                                                                                                                                                                                                                                                                  | no  | no                                                                                                                                                                                                                         |                                                                                                                                                                                                                                       |\n| 2    | 2.2.1    | HEADER_NOT_BEFORE_PACKAGE                 | Check: warns if a KDoc file header is located not before a package directive.<br>Fix: moves this KDoc                                                                                                                                                                                                                                                       | yes | no                                                                                                                                                                                                                         |                                                                                                                                                                                                                                       |\n| 2    | 2.3.1    | KDOC_TRIVIAL_KDOC_ON_FUNCTION             | Check: warns if KDoc contains a single line with words 'return', 'get' or 'set'.                                                                                                                                                                                                                                                                            | no  | no                                                                                                                                                                                                                         |                                                                                                                                                                                                                                       |\n| 2    | 2.4.1    | COMMENT_WHITE_SPACE                       | Check: warns if there is no space between // and comment, and if there is no space between the code and the comment <br>.Fix: adds a white space.                                                                                                                                                                                                           | yes | maxSpaces                                                                                                                                                                                                                  | -                                                                                                                                                                                                                                     |\n| 2    | 2.4.1    | WRONG_NEWLINES_AROUND_KDOC                | Check: warns if there is no new line above and under the comment. Exception on the first comment.<br>Fix: adds a new line.                                                                                                                                                                                                                                  | yes | no                                                                                                                                                                                                                         | -                                                                                                                                                                                                                                     |\n| 2    | 2.4.1    | FIRST_COMMENT_NO_BLANK_LINE               | Check: warns if there is a new line before the first comment.<br>Fix: deletes a new line.                                                                                                                                                                                                                                                                   | yes | no                                                                                                                                                                                                                         | -                                                                                                                                                                                                                                     |\n| 2    | 2.4.1    | IF_ELSE_COMMENTS                          | Check: warns if there is a comment outside of the else block.<br>Fix: adds the comment to the first line in else block.                                                                                                                                                                                                                                     | yes | no                                                                                                                                                                                                                         | -                                                                                                                                                                                                                                     |\n| 2    | 2.4.2    | COMMENTED_OUT_CODE                        | Check: warns if the commented code is detected (when uncommented, can be parsed).                                                                                                                                                                                                                                                                           | no  | no                                                                                                                                                                                                                         | Offset is lost when the joined EOL comments are split again.                                                                                                                                                                          |\n| 3    | 3.1.1    | FILE_IS_TOO_LONG                          | Check: warns if the file has too many lines.<br>Fix: no                                                                                                                                                                                                                                                                                                     | no  | maxSize                                                                                                                                                                                                                    | -                                                                                                                                                                                                                                     |\n| 1    | 3.1.2    | FILE_NAME_MATCH_CLASS                     | Check: warns<br>Fix: no                                                                                                                                                                                                                                                                                                                                     | no  | no                                                                                                                                                                                                                         | Probably, it can be agressively autofixed.                                                                                                                                                                                            |\n| 3    | 3.1.2    | FILE_CONTAINS_ONLY_COMMENTS               | Check: warns if the file contains only comments, imports, and package directive.                                                                                                                                                                                                                                                                            | no  | no                                                                                                                                                                                                                         | -                                                                                                                                                                                                                                     |\n| 3    | 3.1.2    | FILE_INCORRECT_BLOCKS_ORDER               | Check: warns if the general order of code parts is wrong.<br>Fix: rearranges parts of code.                                                                                                                                                                                                                                                                 | yes | no                                                                                                                                                                                                                         | handle other elements that could be present before the package directive (other comments).                                                                                                                                            |\n| 3    | 3.1.2    | FILE_NO_BLANK_LINE_BETWEEN_BLOCKS         | Check: warns if there is not exactly one blank line between the code parts.<br>Fix: leaves a single empty line.                                                                                                                                                                                                                                             | yes | no                                                                                                                                                                                                                         | -                                                                                                                                                                                                                                     |\n| 3    | 3.1.2    | FILE_UNORDERED_IMPORTS                    | Check: warns if the imports are not sorted alphabetically, or there are empty lines among them.<br>Fix: reorders imports.                                                                                                                                                                                                                                   | yes | no                                                                                                                                                                                                                         | -                                                                                                                                                                                                                                     |\n| 3    | 3.1.2    | FILE_WILDCARD_IMPORTS                     | Check: warns if the wildcard imports are used except the cases when they are allowed.                                                                                                                                                                                                                                                                       | no  | allowedWildcards                                                                                                                                                                                                           | -                                                                                                                                                                                                                                     |\n| 3    | 3.1.2    | UNUSED_IMPORT                             | Check: warns if an import is not used.                                                                                                                                                                                                                                                                                                                      | no  | deleteUnusedImport                                                                                                                                                                                                         | -                                                                                                                                                                                                                                     |\n| 3    | 3.1.4    | WRONG_ORDER_IN_CLASS_LIKE_STRUCTURES      | Check: warns if the declaration part of a class, such as a code structure (class, interface, etc.) is not in the proper order.<br>Fix: restores the order according to the code style guide.                                                                                                                                                                | yes | no                                                                                                                                                                                                                         | -                                                                                                                                                                                                                                     |\n| 3    | 3.1.4    | BLANK_LINE_BETWEEN_PROPERTIES             | Check: warns if properties with comments are not separated by a blank line.<br>Fix: fixes the number of blank lines.                                                                                                                                                                                                                                        | yes | no                                                                                                                                                                                                                         | -                                                                                                                                                                                                                                     |\n| 3    | 3.1.4    | WRONG_DECLARATIONS_ORDER                  | Check: if the order of enum values or constant properties inside the companion is not correct.                                                                                                                                                                                                                                                              | yes | no                                                                                                                                                                                                                         | -                                                                                                                                                                                                                                     |\n| 3    | 3.1.5    | TOP_LEVEL_ORDER                           | Check: warns if the top level order is incorrect.                                                                                                                                                                                                                                                                                                           | yes | no                                                                                                                                                                                                                         | -                                                                                                                                                                                                                                     |\n| 3    | 3.2.1    | NO_BRACES_IN_CONDITIONALS_AND_LOOPS       | Check: warns if braces are not used in `if`, `else`, `when`, `for`, `do`, and `while` statements. Exception: single line if statement (ternary operator).<br>Fix: adds missing braces.                                                                                                                                                                      | yes | no                                                                                                                                                                                                                         | -                                                                                                                                                                                                                                     |\n| 3    | 3.2.2    | BRACES_BLOCK_STRUCTURE_ERROR              | Check: warns if non-empty code blocks with braces do not follow the K&R style (1TBS or OTBS style).                                                                                                                                                                                                                                                         | yes | openBraceNewline closeBraceNewline                                                                                                                                                                                         | -                                                                                                                                                                                                                                     |\n| 3    | 3.3.1    | WRONG_INDENTATION                         | Check: warns if an indentation is incorrect.<br>Fix: corrects the indentation.<br><br>Basic cases are covered currently.                                                                                                                                                                                                                                    | yes | extendedIndentOfParameters<br>alignedParameters<br>extendedIndentForExpressionBodies<br>extendedIndentAfterOperators<br>extendedIndentBeforeDot<br>indentationSize                                                         | -                                                                                                                                                                                                                                     |\n| 3    | 3.4.1    | EMPTY_BLOCK_STRUCTURE_ERROR               | Check: warns if an empty block exists or if its style is incorrect.                                                                                                                                                                                                                                                                                         | yes | allowEmptyBlocks styleEmptyBlockWithNewline                                                                                                                                                                                | -                                                                                                                                                                                                                                     |\n| 3    | 3.5.1    | LONG_LINE                                 | Check: warns if the length doesn't exceed the specified length.                                                                                                                                                                                                                                                                                             | no  | lineLength                                                                                                                                                                                                                 | Handle json method in KDoc.                                                                                                                                                                                                           |\n| 3    | 3.6.1    | MORE_THAN_ONE_STATEMENT_PER_LINE          | Check: warns if there is more than one statement per line.                                                                                                                                                                                                                                                                                                  | yes | no                                                                                                                                                                                                                         | -                                                                                                                                                                                                                                     |\n| 3    | 3.6.2    | REDUNDANT_SEMICOLON                       | Check: warns if semicolons are used at the end of a line.<br>Fix: removes the semicolon.                                                                                                                                                                                                                                                                    | yes | no                                                                                                                                                                                                                         | -                                                                                                                                                                                                                                     |\n| 3    | 3.6.2    | WRONG_NEWLINES                            | Check: warns if line breaks do not follow the code style guide.<br>Fix: fixes incorrect line breaks.                                                                                                                                                                                                                                                        | yes | no                                                                                                                                                                                                                         | -                                                                                                                                                                                                                                     |\n| 3    | 3.6.2    | COMPLEX_EXPRESSION                        | Check: warns if a long dot-qualified expression is used in a condition or as an argument.                                                                                                                                                                                                                                                                   | no  | no                                                                                                                                                                                                                         | -                                                                                                                                                                                                                                     |\n| 3    | 3.6.2    | TRAILING_COMMA                            | Check: warns if a trailing comma is missing.                                                                                                                                                                                                                                                                                                                | yes | valueArgument valueParameter indices whenConditions collectionLiteral typeArgument typeParameter destructuringDeclaration                                                                                                  | -                                                                                                                                                                                                                                     |\n| 3    | 3.7.1    | TOO_MANY_BLANK_LINES                      | Check: warns if blank lines are used or placed incorrectly.<br>Fix: removes redundant blank lines.                                                                                                                                                                                                                                                          | yes | no                                                                                                                                                                                                                         |                                                                                                                                                                                                                                       |\n| 3    | 3.8.1    | WRONG_WHITESPACE                          | Check: warns if the usage of horizontal spaces violates the code style guide.<br>Fix: fixes incorrect whitespaces.                                                                                                                                                                                                                                          | yes | no                                                                                                                                                                                                                         | -                                                                                                                                                                                                                                     |\n| 3    | 3.8.1    | TOO_MANY_CONSECUTIVE_SPACES               | Check: warns if there are too many consecutive spaces in a line. Exception: in an enum if there is a configured and single eol comment. <br>Fix: squeezes spaces to 1.                                                                                                                                                                                      | yes | maxSpaces saveInitialFormattingForEnums                                                                                                                                                                                    | -                                                                                                                                                                                                                                     |\n| 3    | 3.9.1    | ENUMS_SEPARATED                           | Check: warns if an enum structure is incorrect: the enum entries should be separated by a comma and a line break, and the last entry should have a semicolon in the end.                                                                                                                                                                                    | yes | no                                                                                                                                                                                                                         | Replace variable to enum if it possible.                                                                                                                                                                                              |\n| 3    | 3.10.2   | LOCAL_VARIABLE_EARLY_DECLARATION          | Check: warns if a local variable is declared not immediately before its usage.<br>Fix (not implemented yet): moves the variable declaration.                                                                                                                                                                                                                | no  | no                                                                                                                                                                                                                         | add auto fix                                                                                                                                                                                                                          |\n| 3    | 3.11.1   | WHEN_WITHOUT_ELSE                         | Check: warns if a `when` statement does not have `else` in the end.<br>Fix: adds `else` when a statement doesn't have it.                                                                                                                                                                                                                                   | yes | no                                                                                                                                                                                                                         | -                                                                                                                                                                                                                                     | If a `when` statement of the enum or sealed type contains all values of the enum, there is no need to have the \"else\" branch.\n| 3    | 3.12.1   | ANNOTATION_NEW_LINE                       | Check: warns if an annotation is not on a new single line.                                                                                                                                                                                                                                                                                                  | yes | no                                                                                                                                                                                                                         | -                                                                                                                                                                                                                                     |\n| 3    | 3.12.2   | PREVIEW_ANNOTATION                        | Check: warns if method, annotated with `@Preview` is not private or has no `Preview` suffix.                                                                                                                                                                                                                                                                | yes | no                                                                                                                                                                                                                         | -                                                                                                                                                                                                                                     |\n| 3    | 3.14.1   | WRONG_MULTIPLE_MODIFIERS_ORDER            | Check: warns if the multiple modifiers in the sequence are in the wrong order. Value identifier supported in Kotlin 1.5                                                                                                                                                                                                                                     | yes | no                                                                                                                                                                                                                         | -                                                                                                                                                                                                                                     |\n| 3    | 3.14.2   | LONG_NUMERICAL_VALUES_SEPARATED           | Check: warns if the value of the integer or float constant is too big.                                                                                                                                                                                                                                                                                      | no  | maxNumberLength maxBlockLength                                                                                                                                                                                             | -                                                                                                                                                                                                                                     |\n| 3    | 3.14.3   | MAGIC_NUMBER                              | Check: warns if there are magic numbers in the code.                                                                                                                                                                                                                                                                                                        | no  | ignoreNumbers, ignoreHashCodeFunction, ignorePropertyDeclaration, ignoreLocalVariableDeclaration, ignoreConstantDeclaration, ignoreCompanionObjectPropertyDeclaration, ignoreEnums, ignoreRanges, ignoreExtensionFunctions | no                                                                                                                                                                                                                                    |\n| 3    | 3.15.1   | STRING_CONCATENATION                      | Check: warns if the concatenation of strings is used in a single line.                                                                                                                                                                                                                                                                                      | yes | no                                                                                                                                                                                                                         | -                                                                                                                                                                                                                                     |\n| 3    | 3.15.2   | STRING_TEMPLATE_CURLY_BRACES              | Check: warns if there are redundant curly braces in the string template.<br> Fix: deletes the curly braces.                                                                                                                                                                                                                                                 | yes | no                                                                                                                                                                                                                         | +                                                                                                                                                                                                                                     |\n| 3    | 3.15.2   | STRING_TEMPLATE_QUOTES                    | Check: warns if there are redundant quotes in the string template.<br> Fix: deletes the quotes and $ symbol.                                                                                                                                                                                                                                                | yes | no                                                                                                                                                                                                                         | +                                                                                                                                                                                                                                     |\n| 3    | 3.16.1   | COLLAPSE_IF_STATEMENTS                    | Check: warns if there are redundant nested if-statements, which could be collapsed into a single statement by concatenating their conditions.                                                                                                                                                                                                               | yes | no                                                                                                                                                                                                                         | -                                                                                                                                                                                                                                     |\n| 3    | 3.16.2   | COMPLEX_BOOLEAN_EXPRESSION                | Check: warns if the boolean expression is complex and can be simplified.<br>Fix: replaces the boolean expression with a simpler one.                                                                                                                                                                                                                        | yes | no                                                                                                                                                                                                                         | +                                                                                                                                                                                                                                     |\n| 3    | 3.17.1   | CONVENTIONAL_RANGE                        | Check: warns if it is possible to replace the range with `until` or replace the `rangeTo` function with a range.<br>Fix: replace range with `until` or replace the `rangeTo` function with a range.                                                                                                                                                         | yes | no                                                                                                                                                                                                                         | -                                                                                                                                                                                                                                     |\n| 3    | 3.18.1   | DEBUG_PRINT                               | Check: warns if there is a printing to console (assumption that it's a debug logging).                                                                                                                                                                                                                                                                      | no  | no                                                                                                                                                                                                                         | -                                                                                                                                                                                                                                     |\n| 4    | 4.1.1    | FLOAT_IN_ACCURATE_CALCULATIONS            | Checks that floating-point values are not used in the arithmetic expressions.<br>Fix: no                                                                                                                                                                                                                                                                    | no  | no                                                                                                                                                                                                                         | Current implementation detects only floating-point constants.                                                                                                                                                                         |\n| 4    | 4.1.3    | SAY_NO_TO_VAR                             | Check: warns if the `var` modifier is used for a local variable (not in a class or at file level), and this var is not used in accumulators.                                                                                                                                                                                                                | no  | no                                                                                                                                                                                                                         | no                                                                                                                                                                                                                                    | Several fixmes related to the search mechanism (VariablesSearch) and fixme for checking reassinment of this var\n| 4    | 4.2.1    | SMART_CAST_NEEDED                         | Check: warns if the casting can be omitted.<br>Fix: Deletes casting.                                                                                                                                                                                                                                                                                        | yes | no                                                                                                                                                                                                                         | -                                                                                                                                                                                                                                     |\n| 4    | 4.2.2    | TYPE_ALIAS                                | Check: if the type reference of a property is longer than expected.                                                                                                                                                                                                                                                                                         | yes | typeReferenceLength                                                                                                                                                                                                        | -                                                                                                                                                                                                                                     |                                                                                                                                                                                                                        |\n| 4    | 4.3.1    | NULLABLE_PROPERTY_TYPE                    | Check: warns if an immutable property is initialized with null, or if the immutable property can have non-nullable type instead of nullable.<br>Fix: suggests the initial value instead of null or changes in the immutable property type.                                                                                                                  | yes | no                                                                                                                                                                                                                         | -                                                                                                                                                                                                                                     |\n| 4    | 4.3.2    | GENERIC_VARIABLE_WRONG_DECLARATION        | Check: warns if variables of generic types don't have an explicit type declaration.<br>Fix: fixes only the variables that have a generic declaration on both sides.                                                                                                                                                                                         | yes | no                                                                                                                                                                                                                         | +                                                                                                                                                                                                                                     |\n| 4    | 4.3.3    | AVOID_NULL_CHECKS                         | Check: warns if the null-check is used explicitly (for example: if (a == null)).                                                                                                                                                                                                                                                                            | yes | no                                                                                                                                                                                                                         | Fix if\\else conditions on null.                                                                                                                                                                                                       |\n| 5    | 5.1.1    | TOO_LONG_FUNCTION                         | Check: warns if the length of a function is too long.                                                                                                                                                                                                                                                                                                       | no  | maxFunctionLength isIncludeHeader                                                                                                                                                                                          |                                                                                                                                                                                                                                       |\n| 5    | 5.1.2    | NESTED_BLOCK                              | Warns if a function has more nested blocks than expected.                                                                                                                                                                                                                                                                                                   | no  | maxNestedBlockQuantit                                                                                                                                                                                                      |                                                                                                                                                                                                                                       |\n| 5    | 5.1.3    | AVOID_NESTED_FUNCTIONS                    | Check: Warns if there are nested functions.<br>Fix: declare the function in the outer scope.                                                                                                                                                                                                                                                                | yes | no                                                                                                                                                                                                                         | +                                                                                                                                                                                                                                     |\n| 5    | 5.1.4    | INVERSE_FUNCTION_PREFERRED                | Check: Warns if a function call with \"!\" can be rewritten to the inverse function (!isEmpty() -> isNotEmpty()).<br>Fix: Rewrites the function call.                                                                                                                                                                                                         | yes | no                                                                                                                                                                                                                         | -                                                                                                                                                                                                                                     |\n| 5    | 5.2.1    | LAMBDA_IS_NOT_LAST_PARAMETER              | Checks that the lambda inside function parameters block is not at the end.                                                                                                                                                                                                                                                                                  | no  | no                                                                                                                                                                                                                         |                                                                                                                                                                                                                                       |\n| 5    | 5.2.2    | TOO_MANY_PARAMETERS                       | Check: Warns if a function contains more parameters than allowed.                                                                                                                                                                                                                                                                                           | no  | maxParameterListSize                                                                                                                                                                                                       |                                                                                                                                                                                                                                       |\n| 5    | 5.2.3    | WRONG_OVERLOADING_FUNCTION_ARGUMENTS      | Check: Warns if a function has overloading instead of using default arguments.                                                                                                                                                                                                                                                                              | no  | no                                                                                                                                                                                                                         |                                                                                                                                                                                                                                       |\n| 5    | 5.2.4    | RUN_BLOCKING_INSIDE_ASYNC                 | Check: Warns if the runBlocking is used inside the async block code.                                                                                                                                                                                                                                                                                        | no  | no                                                                                                                                                                                                                         | -                                                                                                                                                                                                                                     |\n| 5    | 5.2.5    | TOO_MANY_LINES_IN_LAMBDA                  | Checks that the long lambda has parameters.                                                                                                                                                                                                                                                                                                                 | no  | maxLambdaLength                                                                                                                                                                                                            |                                                                                                                                                                                                                                       |\n| 5    | 5.2.6    | CUSTOM_LABEL                              | Check: Warns if using an unnecessary custom label.                                                                                                                                                                                                                                                                                                          | no  | no                                                                                                                                                                                                                         | -                                                                                                                                                                                                                                     |\n| 5    | 5.2.7    | PARAMETER_NAME_IN_OUTER_LAMBDA            | Check: warns if the outer lambda uses an implicit parameter `it`.                                                                                                                                                                                                                                                                                           | no  | no                                                                                                                                                                                                                         | -                                                                                                                                                                                                                                     |\n| 6    | 6.1.1    | SINGLE_CONSTRUCTOR_SHOULD_BE_PRIMARY      | Check: warns if there is only one secondary constructor in a class.<br>Fix: converts it to a primary constructor.                                                                                                                                                                                                                                           | yes | no                                                                                                                                                                                                                         | Support the more complicated logic of the constructor conversion.                                                                                                                                                                     |\n| 6    | 6.1.2    | USE_DATA_CLASS                            | Check: if the class can be made as a data class.                                                                                                                                                                                                                                                                                                            | no  | no                                                                                                                                                                                                                         | yes                                                                                                                                                                                                                                   |\n| 6    | 6.1.3    | EMPTY_PRIMARY_CONSTRUCTOR                 | Check: warns if there is an empty primary constructor.                                                                                                                                                                                                                                                                                                      | yes | no                                                                                                                                                                                                                         | yes                                                                                                                                                                                                                                   |\n| 6    | 6.1.4    | MULTIPLE_INIT_BLOCKS                      | Checks that the classes have only one init block.                                                                                                                                                                                                                                                                                                           | yes | no                                                                                                                                                                                                                         | -                                                                                                                                                                                                                                     |\n| 6    | 6.1.5    | USELESS_SUPERTYPE                         | Checks if the override function can be removed.                                                                                                                                                                                                                                                                                                             | yes | no                                                                                                                                                                                                                         |                                                                                                                                                                                                                                       |\n| 6    | 6.1.6    | CLASS_SHOULD_NOT_BE_ABSTRACT              | Checks if the abstract class has any abstract method. If not, it warns that the class must not be abstract.<br>Fix: deletes the abstract modifier.                                                                                                                                                                                                          | yes | no                                                                                                                                                                                                                         | -                                                                                                                                                                                                                                     |\n| 6    | 6.1.7    | NO_CORRESPONDING_PROPERTY                 | Checks: warns if with using \"backing property\" scheme, the name of a real and a back property are the same.                                                                                                                                                                                                                                                 | no  | no                                                                                                                                                                                                                         | -                                                                                                                                                                                                                                     |\n| 6    | 6.1.8    | CUSTOM_GETTERS_SETTERS                    | Check that no custom getters and setters are used for the properties.                                                                                                                                                                                                                                                                                       | no  | no                                                                                                                                                                                                                         | -                                                                                                                                                                                                                                     |\n| 6    | 6.1.9    | WRONG_NAME_OF_VARIABLE_INSIDE_ACCESSOR    | Checks if the name of a variable is used in the custom getter or setter.                                                                                                                                                                                                                                                                                    | no  | no                                                                                                                                                                                                                         |                                                                                                                                                                                                                                       |\n| 6    | 6.1.10   | TRIVIAL_ACCESSORS_ARE_NOT_RECOMMENDED     | Checks if there are trivial getters or setters. <br> Fix: Delete the trivial getter or setter.                                                                                                                                                                                                                                                              | yes | no                                                                                                                                                                                                                         | -                                                                                                                                                                                                                                     |\n| 6    | 6.1.11   | COMPACT_OBJECT_INITIALIZATION             | Checks if the class instantiation can be wrapped in `apply` for better readability.                                                                                                                                                                                                                                                                         | yes | no                                                                                                                                                                                                                         |                                                                                                                                                                                                                                       |\n| 6    | 6.1.12   | INLINE_CLASS_CAN_BE_USED                  | Check: warns if the class can be transferred to the inline class.                                                                                                                                                                                                                                                                                           | no  | no                                                                                                                                                                                                                         | yes                                                                                                                                                                                                                                   |\n| 6    | 6.2.2    | EXTENSION_FUNCTION_SAME_SIGNATURE         | Checks if an extension function has the same signature as another extension function, and their classes are related.                                                                                                                                                                                                                                        | no  | no                                                                                                                                                                                                                         | +                                                                                                                                                                                                                                     |\n| 6    | 6.2.3    | EXTENSION_FUNCTION_WITH_CLASS             | Check: if the file contains a class, then it can not have extension functions for the same class.                                                                                                                                                                                                                                                           | no  | no                                                                                                                                                                                                                         | -                                                                                                                                                                                                                                     |\n| 6    | 6.2.4    | USE_LAST_INDEX                            | Check: change a property length - 1 to the property lastIndex.                                                                                                                                                                                                                                                                                              | no  | no                                                                                                                                                                                                                         | -                                                                                                                                                                                                                                     |\n| 6    | 6.4.1    | AVOID_USING_UTILITY_CLASS                 | Checks if there is a class/object that can be replaced with the extension function.                                                                                                                                                                                                                                                                         | no  | no                                                                                                                                                                                                                         | -                                                                                                                                                                                                                                     |\n| 6    | 6.4.2    | OBJECT_IS_PREFERRED                       | Check: if class is stateless, then it is preferred to use `object.`                                                                                                                                                                                                                                                                                         | yes | no                                                                                                                                                                                                                         | +                                                                                                                                                                                                                                     |\n| 6    | 6.5.1    | RUN_IN_SCRIPT                             | Checks : if the kts script contains other functions except the run code.                                                                                                                                                                                                                                                                                    | yes | no                                                                                                                                                                                                                         | -                                                                                                                                                                                                                                     |\n"
  },
  {
    "path": "info/build.gradle.kts",
    "content": "import com.saveourtool.diktat.generation.docs.generateAvailableRules\nimport com.saveourtool.diktat.generation.docs.generateCodeStyle\nimport com.saveourtool.diktat.generation.docs.generateFullDoc\nimport com.saveourtool.diktat.generation.docs.generateRulesMapping\n\ntasks.register(\"generateRulesMapping\") {\n    group = \"documentation\"\n    description = \"Generates a table (rules-mapping.md), which maps warning names to chapters in code style\"\n    doFirst {\n        generateRulesMapping()\n    }\n}\n\ntasks.register(\"generateFullDoc\") {\n    group = \"documentation\"\n    description = \"Compile individual chapters into a single markdown document\"\n    doFirst {\n        generateFullDoc(file(\"$rootDir/guide\"), \"diktat-coding-convention.md\")\n    }\n}\n\ntasks.register(\"generateAvailableRules\") {\n    group = \"documentation\"\n    description = \"Generate table for White paper based on available-rules.md and rules-mapping.md\"\n    dependsOn(\"generateRulesMapping\")\n    doFirst {\n        generateAvailableRules(rootDir, file(\"$rootDir/../wp\"))\n    }\n}\n\ntasks.register(\"generateCodeStyle\") {\n    group = \"documentation\"\n    description = \"Adds/updates diktat code style in white paper document\"\n    dependsOn(\"generateFullDoc\")\n    doFirst {\n        generateCodeStyle(file(\"$rootDir/guide\"), file(\"$rootDir/../wp\"))\n    }\n}\n\ntasks.register(\"updateMarkdownDocumentation\") {\n    group = \"documentation\"\n    description = \"Task that aggregates all documentation updates without white paper updates\"\n    dependsOn(\n        \"generateRulesMapping\",\n        \"generateFullDoc\"\n    )\n}\n\ntasks.register(\"updateDocumentation\") {\n    group = \"documentation\"\n    description = \"Task that aggregates all documentation updates\"\n    dependsOn(\n        \"generateRulesMapping\",\n        \"generateAvailableRules\",\n        \"generateFullDoc\",\n        \"generateCodeStyle\"\n    )\n}\n"
  },
  {
    "path": "info/buildSrc/build.gradle.kts",
    "content": "plugins {\n    `kotlin-dsl`\n}\n\nrepositories {\n    mavenCentral()\n    mavenLocal {\n        content {\n            includeGroup(\"com.saveourtool.diktat\")\n        }\n    }\n    flatDir {\n        dirs(\n            \"$rootDir/../../diktat-rules/target\",\n            \"$rootDir/../../diktat-common/target\"\n        )\n    }\n}\n\ndependencies {\n    implementation(\"com.saveourtool.diktat:diktat-rules:$version\")\n}\n"
  },
  {
    "path": "info/buildSrc/gradle.properties",
    "content": "version=1.2.6-SNAPSHOT\n"
  },
  {
    "path": "info/buildSrc/src/main/kotlin/com/saveourtool/diktat/generation/docs/FullDocGenerator.kt",
    "content": "package com.saveourtool.diktat.generation.docs\n\nimport java.io.File\n\n/**\n * Compiles individual chapters of code style into a single document.\n */\nfun generateFullDoc(guideDir: File, fullDocFileName: String) {\n    val GUIDE_PATTERN = \"guide-chapter-\"\n\n    val codeGuideParts = guideDir\n        .listFiles()!!\n        .filter { it.name.contains(GUIDE_PATTERN) }\n\n    val allChapters = codeGuideParts\n        .sortedBy { it.nameWithoutExtension.replace(GUIDE_PATTERN, \"\").toInt() }\n        .map { it.readLines() }\n        .flatten()\n        .joinToString(\"\\n\")\n\n    val tableOfContent = File(guideDir, \"guide-TOC.md\")\n        .readText()\n\n    File(guideDir, fullDocFileName).writeText(\"$tableOfContent\\n\\n$allChapters\")\n}\n"
  },
  {
    "path": "info/buildSrc/src/main/kotlin/com/saveourtool/diktat/generation/docs/GenerationAvailableRules.kt",
    "content": "package com.saveourtool.diktat.generation.docs\n\nimport java.io.File\n\n/**\n * This function parses available-rules.md and rules-mapping.md files to automatically generate table for White paper\n */\n@Suppress(\"MagicNumber\", \"UnsafeCallOnNullableType\")\nfun generateAvailableRules(rootDir: File, wpDir: File) {\n    val ruleMap = File(rootDir, \"rules-mapping.md\").readLines()\n        .drop(2)\n        .map { it.drop(1).dropLast(1).split(\"|\") }\n        .map { RuleDescription(it[0].replace(\"\\\\s+\".toRegex(), \"\"), it[1], it[2]) }\n        .associateBy { it.ruleName }\n    File(rootDir, \"available-rules.md\").readLines()\n        .drop(2)\n        .map { it.drop(1).dropLast(1).split(\"|\") }\n        .map { it[2].replace(\"\\\\s+\".toRegex(), \"\") to it[5] }\n        .forEach { ruleMap[it.first]!!.config = it.second}\n    val newText = File(wpDir, \"sections/appendix.tex\").readLines().toMutableList()\n    newText.removeAll(newText.subList(newText.indexOf(\"\\\\section*{Available Rules}\") + 1, newText.indexOf(\"%CodeStyle\")))\n    var index = newText.indexOf(\"\\\\section*{Available Rules}\") + 1\n    AUTO_TABLE.trimIndent().lines().forEach { newText.add(index++, it) }\n    ruleMap.map { it.value }\n        .map { \"${it.correctRuleName} & ${it.correctCodeStyle} & ${it.autoFix} & ${it.config.replace(\"<br>\", \" \")}\\\\\\\\\" }\n        .forEach { newText.add(index++, it) }\n    AUTO_END.trimIndent().split(\"\\n\").forEach { newText.add(index++, it) }\n\n    File(wpDir, \"sections/appendix.tex\").writeText(newText.joinToString(separator = \"\\n\"))\n}\n\n/**\n * Data class for rule and it's description\n *\n * @property ruleName rule's name\n * @property codeStyle rule's description\n * @property autoFix is rule can fix\n */\n@Suppress(\"UnsafeCallOnNullableType\")\ndata class RuleDescription(val ruleName: String,\n                           val codeStyle: String,\n                           val autoFix: String) {\n    /**\n     * Remove square brackets from code style\n     */\n    val correctCodeStyle = codeStyle.substring(codeStyle.indexOf(\"[\") + 1, codeStyle.indexOf(\"]\")).run {\n        \"\\\\hyperref[sec:$this]{$this}\"\n    }\n\n    /**\n     * Replace space between words with underline for Latex\n     */\n    val correctRuleName = ruleName.replace(\"_\", \"\\\\underline{ }\")\n\n    /**\n     * Parse correctly configuration for Latex\n     */\n    lateinit var config: String\n}\n"
  },
  {
    "path": "info/buildSrc/src/main/kotlin/com/saveourtool/diktat/generation/docs/GenerationDocs.kt",
    "content": "@file:Suppress(\"FILE_NAME_MATCH_CLASS\")\n\npackage com.saveourtool.diktat.generation.docs\n\nimport java.io.File\nimport java.io.PrintWriter\n\n\n/**\n * Adds/updates diktat code style in white paper document.\n */\n@Suppress(\n        \"LoopWithTooManyJumpStatements\",\n        \"LongMethod\",\n        \"MagicNumber\",\n        \"ComplexMethod\",\n        \"NestedBlockDepth\",\n        \"TOO_LONG_FUNCTION\")\nfun generateCodeStyle(guideDir: File, wpDir: File) {\n    val file = File(guideDir, \"diktat-coding-convention.md\")\n    val tempFile = File(wpDir, \"convention.tex\")\n    val lines = file.readLines().toMutableList().drop(1)\n    tempFile.printWriter().use { writer ->\n        val iterator = lines.iterator()\n        writer.writeWithoutApostrophe(\"%CodeStyle\")\n        while (iterator.hasNext()) {\n            val line = iterator.next()\n            if (line.contains(\"## <a name=\\\"c0\\\"></a> Preface\"))\n                break\n            when {\n                line.startsWith(\"#\") -> {\n                    writer.writeWithoutApostrophe(\"\\\\section*{${line.removePrefix(\"#\").trim()}}\")\n                }\n                line.startsWith(\"*\") -> {\n                    writeTableContentLine(writer, line, 0.5)\n                }\n                line.startsWith(\" \") -> {\n                    writeTableContentLine(writer, line, 1.0)\n                }\n                else -> {\n                    writeTableContentLine(writer, line, 0.0)\n                }\n            }\n        }\n\n        while (iterator.hasNext()) {\n            var line = iterator.next()\n            if (line.contains(\"<!--\")) {\n                // for now there are no multiline comments in our doc\n                continue\n            } else if (line.startsWith(\"#\")) {\n                val number = NUMBER_IN_TAG\n                        .find(line)\n                        ?.value\n                        ?.trim('\"')\n                        ?.substring(1)\n                val name = RULE_NAME\n                        .find(line)\n                        ?.value\n                        ?.removePrefix(\"</a>\")\n                        ?.trim()\n                if (name.isNullOrEmpty() || number.isNullOrEmpty()) {\n                    if (number.isNullOrEmpty() && name.isNullOrEmpty()) {\n                        when (line.takeWhile { it == '#' }.count()) {\n                            1 -> writer.writeWithoutApostrophe(\"\"\"\\section*{\\textbf{${line.removePrefix(\"#\").trim()}}}\"\"\")\n                            2 -> writer.writeWithoutApostrophe(\"\"\"\\section*{\\textbf{${line.removePrefix(\"##\").trim()}}}\"\"\")\n                            3 -> writer.writeWithoutApostrophe(\"\"\"\\subsection*{\\textbf{${line.removePrefix(\"###\").trim()}}}\"\"\")\n                            4 -> writer.writeWithoutApostrophe(\"\"\"\\subsubsection*{\\textbf{${line.removePrefix(\"####\").trim()}}}${\"\\n\"}\\leavevmode\\newline\"\"\")\n                            else -> {}\n                        }\n                        continue\n                    }\n                    error(\"String starts with # but has no number or name - $line\")\n                }\n                when (number.count { it == '.' }) {\n                    0 -> writer.writeWithoutApostrophe(\"\"\"\\section*{\\textbf{$name}}\"\"\")\n                    1 -> writer.writeWithoutApostrophe(\"\"\"\\subsection*{\\textbf{$name}}\"\"\")\n                    2 -> writer.writeWithoutApostrophe(\"\"\"\\subsubsection*{\\textbf{$name}}${\"\\n\"}\\leavevmode\\newline\"\"\")\n                    else -> {}\n                }\n                writer.writeWithoutApostrophe(\"\\\\label{sec:${name.getFirstNumber()}}\")\n\n                continue\n            } else if (iterator.hasNext() && line.trim().startsWith(\"```\")) {\n                writer.writeCode(\"\"\"\\begin{lstlisting}[language=Kotlin]\"\"\")\n                line = iterator.next()\n                while (!line.trim().startsWith(\"```\")) {\n                    writer.writeCode(line)\n                    line = iterator.next()\n                }\n                writer.writeCode(\"\"\"\\end{lstlisting}\"\"\")\n                continue\n            } else if (line.trim().startsWith(\"|\")) {\n                val columnNumber = line.count { it == '|' } - 1\n                val columnWidth: Float = (A4_PAPER_WIDTH / columnNumber)  // For now it makes all column width equal\n                val createTable = \"|p{${columnWidth.format(1)}cm}\".repeat(columnNumber).plus(\"|\")\n                writer.writeWithoutApostrophe(\"\"\"\\begin{center}\"\"\")\n                writer.writeWithoutApostrophe(\"\"\"\\begin{tabular}{ $createTable }\"\"\")\n                writer.writeWithoutApostrophe(\"\"\"\\hline\"\"\")\n                val columnNames = TABLE_COLUMN_NAMES\n                        .findAll(line)\n                        .filter { it.value.isNotEmpty() }\n                        .map { it.value.trim() }\n                        .toList()\n                writer.write(columnNames.joinToString(separator = \"&\"))\n                writer.writeWithoutApostrophe(\"\"\"\\\\\"\"\")\n                writer.writeWithoutApostrophe(\"\\\\hline\")\n                iterator.next()\n                line = iterator.next()\n                while (iterator.hasNext() && line.trim().startsWith(\"|\")) {\n                    writer.writeWithoutApostrophe(line\n                            .replace(\"&\", \"\\\\&\")\n                            .replace('|', '&')\n                            .drop(1)\n                            .dropLast(1)\n                            .plus(\"\"\"\\\\\"\"\")\n                            .replace(\"_\", \"\\\\_\")\n                            .replace(ANCHORS, \"\"))\n                    line = iterator.next()\n                }\n                writer.writeWithoutApostrophe(\"\"\"\\hline\"\"\")\n                writer.writeWithoutApostrophe(\"\\\\end{tabular}\")\n                writer.writeWithoutApostrophe(\"\\\\end{center}\")\n            } else {\n                writer.writeWithoutApostrophe(line, false)\n            }\n        }\n    }\n    val appendixFileLines = File(wpDir, \"sections/appendix.tex\")\n            .readLines()\n            .takeWhile { it != \"%CodeStyle\" }\n            .toMutableList()\n    appendixFileLines.addAll(tempFile.readLines())\n    File(wpDir, \"sections/appendix.tex\").writeText(appendixFileLines.joinToString(separator = \"\\n\"))\n    tempFile.delete()\n}\n\nprivate fun PrintWriter.writeWithoutApostrophe(text: String, isCommand: Boolean = true) {\n    this.writeln(text.replaceApostrophe(isCommand))\n}\n\nprivate fun String.replaceApostrophe(isCommand: Boolean): String {\n    if (isCommand){\n        return this\n    }\n    var correctedString = this\n    if (correctedString.contains(\"\\\\\") && (correctedString.contains(\"\"\"\\\\[a-zA-Z]\"\"\".toRegex()))) {\n        correctedString = correctedString.replace(\"\\\\\", \"\\\\textbackslash \")\n    }\n    correctedString = correctedString.replace(\"{\", \"\\\\{\")\n    correctedString = correctedString.replace(\"}\", \"\\\\}\")\n    correctedString = correctedString.replace(\"_\", \"\\\\_\")\n    correctedString = correctedString.replace(ANCHORS, \"\")\n    correctedString = correctedString.replace(\"#\", \"\\\\#\")\n    correctedString = correctedString.replace(\"&\", \"\\\\&\")\n    correctedString = handleHyperlinks(correctedString)\n    correctedString = findBoldOrItalicText(BOLD_TEXT, correctedString, FindType.BOLD)\n    correctedString = findBoldOrItalicText(ITALIC_TEXT, correctedString, FindType.ITALIC)\n    correctedString = findBoldOrItalicText(BACKTICKS_TEXT, correctedString, FindType.BACKTICKS)\n    return correctedString\n}\n\nprivate fun writeTableContentLine(writer: PrintWriter, line: String, numbOfSpaces: Double) {\n    writer.write(\"\\\\hspace{${numbOfSpaces}cm}\")\n    val correctLine = line\n            .trim()\n            .replace(\"[\", \"\")\n            .replace(\"]\", \"\")\n            .replace(\"*\", \"\")\n            .replace(ANCHORS, \"\")\n            //.replace(\"_\", \"\\\\_\")\n            .replace(\"#\", \"\\\\#\")\n            .replace(\"&\", \"\\\\&\")\n    writer.writeWithoutApostrophe(\"\\\\hyperref[sec:${correctLine.getFirstNumber()}]{$correctLine}\")\n}\n\n/**\n * Type of text in markdown to be written in latex\n */\nenum class FindType {\n    BACKTICKS,\n    BOLD,\n    ITALIC,\n    ;\n}\n\nprivate fun handleHyperlinks(line: String): String {\n    var correctedString = line\n    if (correctedString.contains(HYPERLINKS)) {\n        val hyperlinkSubString = HYPERLINKS.findAll(correctedString)\n        hyperlinkSubString.forEach {\n            var (text, link) = HYPERLINKS.find(it.value)!!.destructured\n            // need to replace back, because it is a hyperlink\n            link = link.trim().drop(1).dropLast(1) // drop ( and )\n            link = link.replace(\"\\\\#\", \"#\")\n            link = link.replace(\"\\\\&\", \"&\")\n            //link = link.replace(\"\\\\_\", \"_\")\n            // need to replace ` in hyperlink, because it breaks latex compilation\n            text = text.replace(\"`\", \"\")\n            text = text.trim().drop(1).dropLast(1) // dropping [ and ]\n            val hyperlink = \"\"\"\\href{$link}{$text}\"\"\"\n            correctedString = correctedString.replace(it.value, hyperlink)\n        }\n    }\n\n    return correctedString\n}\n\nprivate fun findBoldOrItalicText(regex: Regex,\n                                 line: String,\n                                 type: FindType): String {\n    val allRegex = regex\n            .findAll(line)\n            .map { it.value }\n            .toMutableList()\n    allRegex.forEachIndexed { index, value ->\n        when (type) {\n            FindType.BOLD, FindType.BACKTICKS -> allRegex[index] = \"\\\\textbf{${value.replace(\"**\", \"\").replace(\"`\", \"\")}}\"\n            FindType.ITALIC -> allRegex[index] = \"\\\\textit{${value.replace(\"*\", \"\")}}\"\n        }\n    }\n    var correctedLine = line.replace(regex, REGEX_PLACEHOLDER)\n    allRegex.forEach {\n        correctedLine = correctedLine.replaceFirst(REGEX_PLACEHOLDER, it)\n    }\n    return correctedLine\n}\n\nprivate fun String.getFirstNumber() = trimStart().takeWhile { it.isDigit() || it == '.' }\n"
  },
  {
    "path": "info/buildSrc/src/main/kotlin/com/saveourtool/diktat/generation/docs/LatexUtils.kt",
    "content": "/**\n * This is a file, that contains utility methods for latex generation\n */\n\npackage com.saveourtool.diktat.generation.docs\n\nimport java.io.PrintWriter\n\n@Suppress(\"VARIABLE_NAME_INCORRECT_FORMAT\")\nval NUMBER_IN_TAG = Regex(\"\\\"([a-z0-9.]*)\\\"\")  // finds \"r1.0.2\"\n@Suppress(\"VARIABLE_NAME_INCORRECT_FORMAT\")\nval RULE_NAME = Regex(\"(</a>[A-Za-z 0-9':.-]*)\")  // get's rule name from ### <a>...</a> Rule name\n@Suppress(\"VARIABLE_NAME_INCORRECT_FORMAT\")\nval BOLD_TEXT = Regex(\"\"\"\\*\\*([^*]+)\\*\\*\"\"\")  // finds bold text in regular lines\n@Suppress(\"VARIABLE_NAME_INCORRECT_FORMAT\")\nval ITALIC_TEXT = Regex(\"\"\"\\*([A-Za-z ]+)\\*\"\"\")  // finds italic text in regular lines\n@Suppress(\"VARIABLE_NAME_INCORRECT_FORMAT\")\nval HYPERLINKS = Regex(\"\"\"(\\[[a-zA-Z 0-9-_`]*])(\\(http[a-z/.#:A-Z-0-9\\\\_]*\\))\"\"\")  // used to find hyperlinks in line\n@Suppress(\"VARIABLE_NAME_INCORRECT_FORMAT\")\nval BACKTICKS_TEXT = Regex(\"\"\"`([^`]*)`\"\"\")  // finds backtick in regular text (not used for now, may be we will need to use it in future)\n@Suppress(\"VARIABLE_NAME_INCORRECT_FORMAT\")\nval ANCHORS = Regex(\"\"\"\\(#([a-zA-Z0-9-.]*)\\)\"\"\")  // finds anchors on rules and deletes them\n@Suppress(\"VARIABLE_NAME_INCORRECT_FORMAT\")\nval TABLE_COLUMN_NAMES = Regex(\"\"\"[A-Za-z ]*\"\"\")  // used to find column names in tables only\n\nconst val REGEX_PLACEHOLDER = \"RE_PL_AC_E_ME\"\n@Suppress(\"CONSTANT_UPPERCASE\")\nconst val A4_PAPER_WIDTH = 15f\nconst val AUTO_TABLE = \"\"\"\n\\scriptsize\n\\begin{longtable}{ |l|p{0.8cm}|p{0.8cm}| p{3cm} | }\n\\hline\n\\multicolumn{4}{|c|}{Available Rules} \\\\\n\\hline\n\\textbf{diKTat rule} & \\textbf{code style} & \\textbf{autofix} &  \\textbf{config} \\\\\n\\hline\n\"\"\"\nconst val AUTO_END = \"\"\"\n\\hline\n\\end{longtable}\n\"\"\"\n\n/**\n * Writes text on a new line and adds one blank line\n *\n * @param text String to be written\n */\nfun PrintWriter.writeln(text: String) {\n    write(text.plus(\"\\n\\n\"))\n}\n\n/**\n * Writes text on a new line. It is used to write code in latex\n *\n * @param code code lines to be printed\n */\nfun PrintWriter.writeCode(code: String) {\n    write(code.plus(\"\\n\"))\n}\n\n/**\n * Transforms float number to float with only one digit after dot\n *\n * @param digits Float number to be transformed\n */\nfun Float.format(digits: Int) = \"%.${digits}f\".format(this)\n"
  },
  {
    "path": "info/buildSrc/src/main/kotlin/com/saveourtool/diktat/generation/docs/WarningsTableGenerator.kt",
    "content": "package com.saveourtool.diktat.generation.docs\n\nimport com.saveourtool.diktat.ruleset.constants.Warnings\nimport com.saveourtool.diktat.ruleset.constants.getChapterByWarning\n\nimport java.io.File\n\n/**\n * Path to diktat code style guide, which has links to code style chapters\n */\nconst val DIKTAT_GUIDE: String = \"guide/diktat-coding-convention.md#\"\n\n/**\n * Generates a table, which maps warning names to chapters in code style\n */\n@Suppress(\"MagicNumber\")\nfun generateRulesMapping() {\n    // excluding dummy warning\n    val allWarnings = Warnings.values().filterNot { it == Warnings.DUMMY_TEST_WARNING } as MutableList<Warnings>\n    allWarnings.sortBy { warn ->\n        val numbers = warn.ruleId.split(\".\")\n        val chapter = numbers[0].toInt()\n        val subChapter = numbers[1].toInt()\n        val rule = numbers[2].toInt()\n\n        // small hacky trick to compare rules like 1.1.13 properly (sorting using numbers instead of lexicographically)\n        chapter * 100_000 + subChapter * 100 + rule\n    }\n\n    val maxRuleIdLength = allWarnings\n        .maxBy { it.ruleId.length }\n        ?.ruleId\n        ?.length\n        ?: 0\n    val maxRuleNameLength = allWarnings\n        .maxBy { it.name.length }\n        ?.name\n        ?.length\n        ?: 0\n\n    val tableWithWarnings = allWarnings.joinToString(\"\\n\") { warn ->\n        \"| ${warn.name} | [${warn.ruleId}](${DIKTAT_GUIDE}r${warn.ruleId}) | ${if (warn.canBeAutoCorrected) \"yes\" else \"no\"} | ${warn.getChapterByWarning().title} |\"\n    }\n\n    val chaptersLength = allWarnings.map { it.getChapterByWarning().title }.maxBy { it.length }?.length ?: 0\n\n    val header = \"| Diktat Rule | Code Style | Auto-fixed? | Chapter |\\n\"\n    val separator = \"| ${\"-\".repeat(maxRuleNameLength)} | ${\"-\".repeat(maxRuleIdLength)} | --- | ${\"-\".repeat(chaptersLength)} |\\n\"\n    File(\"rules-mapping.md\").writeText(\"$header$separator$tableWithWarnings\")\n}\n"
  },
  {
    "path": "info/gradle/wrapper/gradle-wrapper.properties",
    "content": "distributionBase=GRADLE_USER_HOME\ndistributionPath=wrapper/dists\ndistributionUrl=https\\://services.gradle.org/distributions/gradle-8.11.1-bin.zip\nzipStoreBase=GRADLE_USER_HOME\nzipStorePath=wrapper/dists\n"
  },
  {
    "path": "info/gradlew",
    "content": "#!/usr/bin/env sh\n\n#\n# Copyright 2015 the original author or authors.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#      https://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n#\n\n##############################################################################\n##\n##  Gradle start up script for UN*X\n##\n##############################################################################\n\n# Attempt to set APP_HOME\n# Resolve links: $0 may be a link\nPRG=\"$0\"\n# Need this for relative symlinks.\nwhile [ -h \"$PRG\" ] ; do\n    ls=`ls -ld \"$PRG\"`\n    link=`expr \"$ls\" : '.*-> \\(.*\\)$'`\n    if expr \"$link\" : '/.*' > /dev/null; then\n        PRG=\"$link\"\n    else\n        PRG=`dirname \"$PRG\"`\"/$link\"\n    fi\ndone\nSAVED=\"`pwd`\"\ncd \"`dirname \\\"$PRG\\\"`/\" >/dev/null\nAPP_HOME=\"`pwd -P`\"\ncd \"$SAVED\" >/dev/null\n\nAPP_NAME=\"Gradle\"\nAPP_BASE_NAME=`basename \"$0\"`\n\n# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.\nDEFAULT_JVM_OPTS='\"-Xmx64m\" \"-Xms64m\"'\n\n# Use the maximum available, or set MAX_FD != -1 to use that value.\nMAX_FD=\"maximum\"\n\nwarn () {\n    echo \"$*\"\n}\n\ndie () {\n    echo\n    echo \"$*\"\n    echo\n    exit 1\n}\n\n# OS specific support (must be 'true' or 'false').\ncygwin=false\nmsys=false\ndarwin=false\nnonstop=false\ncase \"`uname`\" in\n  CYGWIN* )\n    cygwin=true\n    ;;\n  Darwin* )\n    darwin=true\n    ;;\n  MINGW* )\n    msys=true\n    ;;\n  NONSTOP* )\n    nonstop=true\n    ;;\nesac\n\nCLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar\n\n\n# Determine the Java command to use to start the JVM.\nif [ -n \"$JAVA_HOME\" ] ; then\n    if [ -x \"$JAVA_HOME/jre/sh/java\" ] ; then\n        # IBM's JDK on AIX uses strange locations for the executables\n        JAVACMD=\"$JAVA_HOME/jre/sh/java\"\n    else\n        JAVACMD=\"$JAVA_HOME/bin/java\"\n    fi\n    if [ ! -x \"$JAVACMD\" ] ; then\n        die \"ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME\n\nPlease set the JAVA_HOME variable in your environment to match the\nlocation of your Java installation.\"\n    fi\nelse\n    JAVACMD=\"java\"\n    which java >/dev/null 2>&1 || die \"ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.\n\nPlease set the JAVA_HOME variable in your environment to match the\nlocation of your Java installation.\"\nfi\n\n# Increase the maximum file descriptors if we can.\nif [ \"$cygwin\" = \"false\" -a \"$darwin\" = \"false\" -a \"$nonstop\" = \"false\" ] ; then\n    MAX_FD_LIMIT=`ulimit -H -n`\n    if [ $? -eq 0 ] ; then\n        if [ \"$MAX_FD\" = \"maximum\" -o \"$MAX_FD\" = \"max\" ] ; then\n            MAX_FD=\"$MAX_FD_LIMIT\"\n        fi\n        ulimit -n $MAX_FD\n        if [ $? -ne 0 ] ; then\n            warn \"Could not set maximum file descriptor limit: $MAX_FD\"\n        fi\n    else\n        warn \"Could not query maximum file descriptor limit: $MAX_FD_LIMIT\"\n    fi\nfi\n\n# For Darwin, add options to specify how the application appears in the dock\nif $darwin; then\n    GRADLE_OPTS=\"$GRADLE_OPTS \\\"-Xdock:name=$APP_NAME\\\" \\\"-Xdock:icon=$APP_HOME/media/gradle.icns\\\"\"\nfi\n\n# For Cygwin or MSYS, switch paths to Windows format before running java\nif [ \"$cygwin\" = \"true\" -o \"$msys\" = \"true\" ] ; then\n    APP_HOME=`cygpath --path --mixed \"$APP_HOME\"`\n    CLASSPATH=`cygpath --path --mixed \"$CLASSPATH\"`\n\n    JAVACMD=`cygpath --unix \"$JAVACMD\"`\n\n    # We build the pattern for arguments to be converted via cygpath\n    ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`\n    SEP=\"\"\n    for dir in $ROOTDIRSRAW ; do\n        ROOTDIRS=\"$ROOTDIRS$SEP$dir\"\n        SEP=\"|\"\n    done\n    OURCYGPATTERN=\"(^($ROOTDIRS))\"\n    # Add a user-defined pattern to the cygpath arguments\n    if [ \"$GRADLE_CYGPATTERN\" != \"\" ] ; then\n        OURCYGPATTERN=\"$OURCYGPATTERN|($GRADLE_CYGPATTERN)\"\n    fi\n    # Now convert the arguments - kludge to limit ourselves to /bin/sh\n    i=0\n    for arg in \"$@\" ; do\n        CHECK=`echo \"$arg\"|egrep -c \"$OURCYGPATTERN\" -`\n        CHECK2=`echo \"$arg\"|egrep -c \"^-\"`                                 ### Determine if an option\n\n        if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then                    ### Added a condition\n            eval `echo args$i`=`cygpath --path --ignore --mixed \"$arg\"`\n        else\n            eval `echo args$i`=\"\\\"$arg\\\"\"\n        fi\n        i=`expr $i + 1`\n    done\n    case $i in\n        0) set -- ;;\n        1) set -- \"$args0\" ;;\n        2) set -- \"$args0\" \"$args1\" ;;\n        3) set -- \"$args0\" \"$args1\" \"$args2\" ;;\n        4) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" ;;\n        5) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" ;;\n        6) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" ;;\n        7) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" \"$args6\" ;;\n        8) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" \"$args6\" \"$args7\" ;;\n        9) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" \"$args6\" \"$args7\" \"$args8\" ;;\n    esac\nfi\n\n# Escape application args\nsave () {\n    for i do printf %s\\\\n \"$i\" | sed \"s/'/'\\\\\\\\''/g;1s/^/'/;\\$s/\\$/' \\\\\\\\/\" ; done\n    echo \" \"\n}\nAPP_ARGS=`save \"$@\"`\n\n# Collect all arguments for the java command, following the shell quoting and substitution rules\neval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS \"\\\"-Dorg.gradle.appname=$APP_BASE_NAME\\\"\" -classpath \"\\\"$CLASSPATH\\\"\" org.gradle.wrapper.GradleWrapperMain \"$APP_ARGS\"\n\nexec \"$JAVACMD\" \"$@\"\n"
  },
  {
    "path": "info/gradlew.bat",
    "content": "@rem\r\n@rem Copyright 2015 the original author or authors.\r\n@rem\r\n@rem Licensed under the Apache License, Version 2.0 (the \"License\");\r\n@rem you may not use this file except in compliance with the License.\r\n@rem You may obtain a copy of the License at\r\n@rem\r\n@rem      https://www.apache.org/licenses/LICENSE-2.0\r\n@rem\r\n@rem Unless required by applicable law or agreed to in writing, software\r\n@rem distributed under the License is distributed on an \"AS IS\" BASIS,\r\n@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r\n@rem See the License for the specific language governing permissions and\r\n@rem limitations under the License.\r\n@rem\r\n\r\n@if \"%DEBUG%\" == \"\" @echo off\r\n@rem ##########################################################################\r\n@rem\r\n@rem  Gradle startup script for Windows\r\n@rem\r\n@rem ##########################################################################\r\n\r\n@rem Set local scope for the variables with windows NT shell\r\nif \"%OS%\"==\"Windows_NT\" setlocal\r\n\r\nset DIRNAME=%~dp0\r\nif \"%DIRNAME%\" == \"\" set DIRNAME=.\r\nset APP_BASE_NAME=%~n0\r\nset APP_HOME=%DIRNAME%\r\n\r\n@rem Resolve any \".\" and \"..\" in APP_HOME to make it shorter.\r\nfor %%i in (\"%APP_HOME%\") do set APP_HOME=%%~fi\r\n\r\n@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.\r\nset DEFAULT_JVM_OPTS=\"-Xmx64m\" \"-Xms64m\"\r\n\r\n@rem Find java.exe\r\nif defined JAVA_HOME goto findJavaFromJavaHome\r\n\r\nset JAVA_EXE=java.exe\r\n%JAVA_EXE% -version >NUL 2>&1\r\nif \"%ERRORLEVEL%\" == \"0\" goto execute\r\n\r\necho.\r\necho ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.\r\necho.\r\necho Please set the JAVA_HOME variable in your environment to match the\r\necho location of your Java installation.\r\n\r\ngoto fail\r\n\r\n:findJavaFromJavaHome\r\nset JAVA_HOME=%JAVA_HOME:\"=%\r\nset JAVA_EXE=%JAVA_HOME%/bin/java.exe\r\n\r\nif exist \"%JAVA_EXE%\" goto execute\r\n\r\necho.\r\necho ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%\r\necho.\r\necho Please set the JAVA_HOME variable in your environment to match the\r\necho location of your Java installation.\r\n\r\ngoto fail\r\n\r\n:execute\r\n@rem Setup the command line\r\n\r\nset CLASSPATH=%APP_HOME%\\gradle\\wrapper\\gradle-wrapper.jar\r\n\r\n\r\n@rem Execute Gradle\r\n\"%JAVA_EXE%\" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% \"-Dorg.gradle.appname=%APP_BASE_NAME%\" -classpath \"%CLASSPATH%\" org.gradle.wrapper.GradleWrapperMain %*\r\n\r\n:end\r\n@rem End local scope for the variables with windows NT shell\r\nif \"%ERRORLEVEL%\"==\"0\" goto mainEnd\r\n\r\n:fail\r\nrem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of\r\nrem the _cmd.exe /c_ return code!\r\nif  not \"\" == \"%GRADLE_EXIT_CONSOLE%\" exit 1\r\nexit /b 1\r\n\r\n:mainEnd\r\nif \"%OS%\"==\"Windows_NT\" endlocal\r\n\r\n:omega\r\n"
  },
  {
    "path": "info/guide/diktat-coding-convention.md",
    "content": "<img src=\"logo.svg\" width=\"64px\"/>\n\n## Kotlin Coding Style Guide (Diktat Code Style), v.1.0.0\n\nI [Preface](#c0)\n* [I.I Purpose of this document](#c0.1)\n* [I.II General principles](#c0.2)\n* [I.III Terminology](#c0.3)\n* [I.IV Exceptions](#c0.4)\n\n[1. Naming](#c1)\n\n* [1.1 Identifiers](#c1.1)\n* [1.2 Packages](#c1.2)\n* [1.3 Classes, enumerations, interfaces](#c1.3)\n* [1.4 Functions](#c1.4)\n* [1.5 Constants](#c1.5)\n* [1.6 Non-constant fields (variables)](#c1.6)\n    * [1.6.1 Non-constant field name](#r1.6.1)\n    * [1.6.2 Boolean variable names with negative meaning](#r1.6.2)\n\n[2. Comments](#c2)\n* [2.1 General form of Kdoc](#c2.1)\n    * [2.1.1 Using KDoc for the public, protected, or internal code elements](#r2.1.1)\n    * [2.1.2 Describing methods that have arguments, a return value, or can throw an exception in the KDoc block](#r2.1.2)\n    * [2.1.3 Only one space between the Kdoc tag and content. Tags are arranged in the order.](#r2.1.3)\n* [2.2 Adding comments on the file header](#c2.2)\n* [2.3 Comments on the function header](#c2.3)\n* [2.4 Code comments](#c2.4)\n    * [2.4.1 Add a blank line between the body of the comment and Kdoc tag-blocks](#r2.4.1)\n    * [2.4.2 Do not comment on unused code blocks](#r2.4.2)\n    * [2.4.3 Code delivered to the client should not contain TODO/FIXME comments](#r2.4.3)\n\n[3. General formatting (typesetting)](#c3)\n* [3.1 File-related rules](#c3.1)\n    * [3.1.1 Avoid files that are too long](#r3.1.1)\n    * [3.1.2 Code blocks in the source file should be separated by one blank line](#r3.1.2)\n    * [3.1.3 Import statements order](#r3.1.3)\n    * [3.1.4 Order of declaration parts of class-like code structures](#r3.1.4)\n    * [3.1.5 Order of declaration of top-level code structures](#r3.1.5)\n* [3.2 Braces](#c3.2)\n    * [3.2.1 Using braces in conditional statements and loop blocks](#r3.2.1)\n    * [3.2.2 Opening braces are placed at the end of the line in *non-empty* blocks and block structures](#r3.2.2)\n* [3.3 Indentation](#c3.3)\n* [3.4 Empty blocks](#c3.4)\n* [3.5 Line length](#c3.5)\n* [3.6 Line breaks (newlines)](#c3.6)\n    * [3.6.1 Each line can have a maximum of one statement](#r3.6.1)\n    * [3.6.2 Rules for line-breaking](#r3.6.2)\n* [3.7 Using blank lines](#c3.7)\n* [3.8 Horizontal space](#c3.8)\n    * [3.8.1 Usage of whitespace for code separation](#r3.8.1)\n    * [3.8.2 No spaces for horizontal alignment](#r3.8.2)\n* [3.9 Enumerations](#c3.9)\n* [3.10 Variable declaration](#c3.10)\n    * [3.10.1 Declare one variable per line](#r3.10.1)\n    * [3.10.2 Variables should be declared near the line where they are first used](#r3.10.2)\n* [3.11 'When' expression](#c3.11)\n* [3.12 Annotations](#c3.12)\n* [3.13 Block comments](#c3.13)\n* [3.14 Modifiers and constant values](#c3.14)\n    * [3.14.1 Declaration with multiple modifiers](#r3.14.1)\n    * [3.14.2 Separate long numerical values with an underscore](#r3.14.2)\n * [3.15 Strings](#c3.15)\n     * [3.15.1 Concatenation of Strings](#r3.15.1)\n     * [3.15.2 String template format](#r3.15.2)\n * [3.16 Conditional statements](#c3.16)\n     * [3.16.1 Collapsing redundant nested if-statements](#r3.16.1)\n     * [3.16.2 Too complex conditions](#r3.16.2)\n\n[4. Variables and types](#c4)\n* [4.1 Variables](#c4.1)\n    * [4.1.1 Do not use Float and Double types when accurate calculations are needed](#r4.1.1)\n    * [4.1.2 Comparing numeric float type values](#r4.1.2)\n    * [4.1.3 Try to use 'val' instead of 'var' for variable declaration [SAY_NO_TO_VAR]](#r4.1.3)\n* [4.2 Types](#c4.2)\n    * [4.2.1 Use Contracts and smart cast as much as possible](#r4.2.1)\n    * [4.2.2 Try to use type alias to represent types making code more readable](#r4.2.2)\n* [4.3 Null safety and variable declarations](#c4.3)\n    * [4.3.1 Avoid declaring variables with nullable types, especially from Kotlin stdlib](#r4.3.1)\n    * [4.3.2 Variables of generic types should have an explicit type declaration](#r4.3.2)\n    * [4.3.3 Null-safety](#r4.3.3)\n\n[5. Functions](#c5)\n* [5.1 Function design](#c5.1)\n    * [5.1.1 Avoid functions that are too long ](#r5.1.1)\n    * [5.1.2 Avoid deep nesting of function code blocks, limiting to four levels](#r5.1.2)\n    * [5.1.3 Avoid using nested functions](#r5.1.3)\n    * [5.1.4 Negated function calls](#r5.1.4)\n* [5.2 Function arguments](#c5.2)\n    * [5.2.1 The lambda parameter of the function should be placed at the end of the argument list](#r5.2.1)\n    * [5.2.2 Number of function parameters should be limited to five](#r5.2.2)\n    * [5.2.3 Use default values for function arguments instead of overloading them](#r5.2.3)\n    * [5.2.4 Synchronizing code inside asynchronous code](#r5.2.4)\n    * [5.2.5 Long lambdas should have explicit parameters](#r5.2.5)\n    * [5.2.6 Avoid using unnecessary, custom label](#r5.2.6)\n\n[6. Classes, interfaces, and extension functions](#c6)\n* [6.1 Classes](#c6.1)\n    * [6.1.1 Denoting a class with a single constructor](#r6.1.1)\n    * [6.1.2 Prefer data classes instead of classes without any functional logic](#r6.1.2)\n    * [6.1.3 Do not use the primary constructor if it is empty or useless](#r6.1.3)\n    * [6.1.4 Do not use redundant init blocks in your class](#r6.1.4)\n    * [6.1.5 Explicit supertype qualification](#r6.1.5)\n    * [6.1.6 Abstract class should have at least one abstract method](#r6.1.6)\n    * [6.1.7 When using the \"implicit backing property\" scheme, the name of real and back property should be the same](#r6.1.7)\n    * [6.1.8 Avoid using custom getters and setters](#r6.1.8)\n    * [6.1.9 Never use the name of a variable in the custom getter or setter (possible_bug)](#r6.1.9)\n    * [6.1.10 No trivial getters and setters are allowed in the code](#r6.1.10)\n    * [6.1.11 Use 'apply' for grouping object initialization](#r6.1.11)\n    * [6.1.12 Prefer Inline classes when a class has a single property](#r6.1.12)\n* [6.2 Extension functions](#c6.2)\n    * [6.2.1 Use extension functions for making logic of classes less coupled](#r6.2.1)\n    * [6.2.2 No extension functions with the same name and signature if they extend base and inheritor classes (possible_bug)](#r6.2.2)\n    * [6.2.3 Don't use extension functions for the class in the same file](#r6.2.3)\n* [6.3 Interfaces](#c6.3)\n* [6.4 Objects](#c6.4)\n    * [6.4.1 Instead of using utility classes/objects, use extensions](#r6.4.1)\n    * [6.4.2 Objects should be used for Stateless Interfaces](#r6.4.2)\n* [6.5 Kts Files](#c6.5)\n    * [6.5.1 kts files should wrap logic into top-level scope](#r6.5.1)\n\n## <a name=\"c0\"></a> Preface\n <!-- =============================================================================== -->\n### <a name=\"c0.1\"></a> Purpose of this document\n\nThe purpose of this document is to provide a specification that software developers could reference to enhance their ability to write consistent, easy-to-read, and high-quality code.\nSuch a specification will ultimately improve software development efficiency and product competitiveness.\nFor the code to be considered high-quality, it must entail the following characteristics:\n1.\tSimplicity\n2.\tMaintainability\n3.\tReliability\n4.\tTestability\n5.\tEfficiency\n6.\tPortability\n7.\tReusability\n\n\n<!-- =============================================================================== -->\n### <a name=\"c0.2\"></a> General principles\n\nLike other modern programming languages, Kotlin is an advanced programming language that complies with the following general principles:\n1.\tClarity — a necessary feature of programs that are easy to maintain and refactor.\n2.\tSimplicity — a code is easy to understand and implement.\n3.\tConsistency — enables a code to be easily modified, reviewed, and understood by the team members. Unification is particularly important when the same team works on the same project, utilizing similar styles enabling a code to be easily modified, reviewed, and understood by the team members.\n\nAlso, we need to consider the following factors when programming on Kotlin:\n\n1. Writing clean and simple Kotlin code\n\n    Kotlin combines two of the main programming paradigms: functional and object-oriented.\n    Both of these paradigms are trusted and well-known software engineering practices.\n    As a young programming language, Kotlin is built on top of well-established languages such as Java, C++, C#, and Scala.\n    This enables Kotlin to introduce many features that help a developer write cleaner, more readable code while also reducing the number of complex code structures. For example, type and null safety, extension functions, infix syntax, immutability, val/var differentiation, expression-oriented features, \"when\" statements, much easier work with collections, type auto conversion, and other syntactic sugar.\n\n2. Following Kotlin idioms\n\n    The author of Kotlin, Andrey Breslav, mentioned that Kotlin is both pragmatic and practical, but not academic.\n    Its pragmatic features enable ideas to be transformed into real working software easily. Kotlin is closer to natural languages than its predecessors, and it implements the following design principles: readability, reusability, interoperability, security, and tool-friendliness (https://blog.jetbrains.com/kotlin/2018/10/kotlinconf-2018-announcements/).\n\n3. Using Kotlin efficiently\n\n    Some Kotlin features can help you to write higher-performance code: including rich coroutine library, sequences, inline functions/classes, arrays of basic types, tailRec, and CallsInPlace of contract.\n\n<!-- =============================================================================== -->\n### <a name=\"c0.3\"></a> Terminology\n\n**Rules** — conventions that should be followed when programming.\n\n**Recommendations** — conventions that should be considered when programming.\n\n**Explanation** — necessary explanations of rules and recommendations.\n\n**Valid Example** — recommended examples of rules and recommendations.\n\n**Invalid Example** — not recommended examples of rules and recommendations.\n\nUnless otherwise stated, this specification applies to versions 1.3 and later of Kotlin.\n\n<!-- =============================================================================== -->\n### <a name=\"c0.4\"></a> Exceptions\n\nEven though exceptions may exist, it is essential to understand why rules and recommendations are needed.\nDepending on a project situation or personal habits, you can break some of the rules. However, remember that one exception may lead to many and eventually can destroy code consistency. As such, there should be very few exceptions.\nWhen modifying open-source code or third-party code, you can choose to use the code style from this open-source project (instead of using the existing specifications) to maintain consistency.\nSoftware that is directly based on the Android native operating system interface, such as the Android Framework, remains consistent with the Android style.\n# <a name=\"c1\"></a> 1. Naming\nIn programming, it is not always easy to meaningfully and appropriately name variables, functions, classes, etc. Using meaningful names helps to clearly express your code's main ideas and functionality and avoid misinterpretation, unnecessary coding and decoding, \"magic\" numbers, and inappropriate abbreviations.\n\nNote: The source file encoding format (including comments) must be UTF-8 only. The ASCII horizontal space character (0x20, that is, space) is the only permitted whitespace character. Tabs should not be used for indentation.\n\n<!-- =============================================================================== -->\n### <a name=\"c1.1\"></a> 1.1 Identifiers\nThis section describes the general rules for naming identifiers.\n#### <a name=\"r1.1.1\"></a> 1.1.1 Identifiers naming conventions\n\nFor identifiers, use the following naming conventions:\n1.\tAll identifiers should use only ASCII letters or digits, and the names should match regular expressions `\\w{2,64}`.\nExplanation: Each valid identifier name should match the regular expression `\\w{2,64}`.\n`{2,64}` means that the name length is 2 to 64 characters, and the length of the variable name should be proportional to its life range, functionality, and responsibility.\nName lengths of less than 31 characters are generally recommended. However, this depends on the project. Otherwise, a class declaration with generics or inheritance from a superclass can cause line breaking.\nNo special prefix or suffix should be used in names. The following examples are inappropriate names: name_, mName, s_name, and kName.\n\n2.\tChoose file names that would describe the content. Use camel case (PascalCase) and `.kt` extension.\n\n3.\tTypical examples of naming:\n\n| Meaning | Correct |Incorrect|\n| ---- | ---- | ---- |\n| \"XML Http Request\" | XmlHttpRequest | XMLHTTPRequest |\n| \"new customer ID\" | newCustomerId | newCustomerID |\n| \"inner stopwatch\" | innerStopwatch | innerStopWatch |\n| \"supports IPv6 on iOS\" | supportsIpv6OnIos | supportsIPv6OnIOS |\n| \"YouTube importer\" | YouTubeImporter | YoutubeImporter |\n\n4.\tThe usage of (``) and free naming for functions and identifiers are prohibited. For example, the following code is not recommended:\n\n```kotlin\nval `my dummy name-with-minus` = \"value\"\n```\n\nThe only exception is function names in `Unit tests.`\n\n5.\tBackticks (``) should not be used for identifiers, except the names of test methods (marked with @Test annotation):\n```kotlin\n @Test fun `my test`() { /*...*/ }\n```\n6.  The following table contains some characters that may cause confusion. Be careful when using them as identifiers. To avoid issues, use other names instead.\n\n| Expected      | Confusing name           | Suggested name   |\n| ------------- | ------------------------ | ---------------- |\n| 0 (zero)      | O, D                     | obj, dgt         |\n| 1 (one)       | I, l                     | it, ln, line     |\n| 2 (two)       | Z                        | n1, n2           |\n| 5 (five)      | S                        | xs, str          |\n| 6 (six)       | e                        | ex, elm          |\n| 8 (eight)     | B                        | bt, nxt          |\n| n,h           | h,n                      | nr, head, height |\n| rn, m         | m,rn                     | mbr, item        |\n\n**Exceptions:**\n- The i,j,k variables used in loops are part of the industry standard. One symbol can be used for such variables.\n- The `e` variable can be used to catch exceptions in catch block: `catch (e: Exception) {}`\n- The Java community generally does not recommend the use of prefixes. However, when developing Android code, you can use the s and m prefixes for static and non-public non-static fields, respectively.\nNote that prefixing can also negatively affect the style and the auto-generation of getters and setters.\n\n| Type | Naming style |\n| ---- | ---- |\n| Interfaces, classes, annotations, enumerated types, and object type names | Camel case, starting with a capital letter. Test classes have a Test suffix. The filename is 'TopClassName'.kt.  |\n| Class fields, local variables, methods, and method parameters | Camel case starting with a low case letter. Test methods can be underlined with '_'; the only exception is [backing properties](#r6.1.7).\n| Static constants and enumerated values | Only uppercase underlined with '_' |\n| Generic type variable | Single capital letter, which can be followed by a number, for example: `E, T, U, X, T2` |\n| Exceptions | Same as class names, but with a suffix Exception, for example: `AccessException` and `NullPointerException`|\n\n<!-- =============================================================================== -->\n### <a name=\"c1.2\"></a> 1.2 Packages\n\n#### <a name=\"r1.2.1\"></a> Rule 1.2.1 Package names dots\nPackage names are in lower case and separated by dots. Code developed within your company should start with `your.company.domain.` Numbers are permitted in package names.\nEach file should have a `package` directive.\nPackage names are all written in lowercase, and consecutive words are concatenated together (no underscores). Package names should contain both the product or module names and the department (or team) name to prevent conflicts with other teams.  Numbers are not permitted. For example: `org.apache.commons.lang3`, `xxx.yyy.v2`.\n\n**Exceptions:**\n\n- In certain cases, such as open-source projects or commercial cooperation, package names should not start with `your.company.domain.`\n- If the package name starts with a number or other character that cannot be used at the beginning of the Java/Kotlin package name, then underscores are allowed. For example: `com.example._123name`.\n- Underscores are sometimes permitted if the package name contains reserved Java/Kotlin keywords, such as `org.example.hyphenated_name`, `int_.example`.\n\n**Valid example**:\n```kotlin\npackage your.company.domain.mobilecontrol.views\n```\n\n<!-- =============================================================================== -->\n### <a name=\"c1.3\"></a> 1.3 Classes, enumerations, typealias, interfaces\nThis section describes the general rules for naming classes, enumerations, and interfaces.\n### <a name=\"r1.3.1\"></a> 1.3.1 Classes, enumerations, typealias, interface names use Camel case\nClasses, enumerations, and interface names use `UpperCamelCase` nomenclature. Follow the naming rules described below:\n1.\tA class name is usually a noun (or a noun phrase) denoted using the camel case nomenclature, such as UpperCamelCase. For example: `Character` or `ImmutableList`.\nAn interface name can also be a noun or noun phrase (such as `List`) or an adjective or adjective phrase (such as `Readable`).\nNote that verbs are not used to name classes. However, nouns (such as `Customer`, `WikiPage`, and `Account`) can be used. Try to avoid using vague words such as `Manager` and `Process`.\n\n2.\tTest classes start with the name of the class they are testing and end with 'Test'. For example, `HashTest` or `HashIntegrationTest`.\n\n**Invalid example**:\n```kotlin\nclass marcoPolo {}\nclass XMLService {}\ninterface TAPromotion {}\nclass info {}\n```\n\n**Valid example**:\n```kotlin\nclass MarcoPolo {}\nclass XmlService {}\ninterface TaPromotion {}\nclass Order {}\n```\n\n<!-- =============================================================================== -->\n### <a name=\"c1.4\"></a> 1.4 Functions\nThis section describes the general rules for naming functions.\n### <a name=\"r1.4.1\"></a> 1.4.1 Function names should be in camel case\nFunction names should use `lowerCamelCase` nomenclature. Follow the naming rules described below:\n1.\tFunction names are usually verbs or verb phrases denoted with the camel case nomenclature (`lowerCamelCase`).\nFor example: `sendMessage`, `stopProcess`, or `calculateValue`.\nTo name functions, use the following formatting rules:\n\na) To get, modify, or calculate a certain value: get + non-boolean field(). Note that the Kotlin compiler automatically generates getters for some classes, applying the special syntax preferred for the 'get' fields: kotlin private val field: String get() { }. kotlin private val field: String get() { }.\n```kotlin\nprivate val field: String\nget() {\n}\n```\nNote: The calling property access syntax is preferred to call getter directly. In this case, the Kotlin compiler automatically calls the corresponding getter.\n\nb) `is` + boolean variable name()\n\nc) `set` + field/attribute name(). However, note that the syntax and code generation for Kotlin are completely the same as those described for the getters in point a.\n\nd) `has` + Noun / adjective ()\n\ne) verb()\nNote: Note: Verb are primarily used for the action objects, such as `document.print ()`\n\nf) verb + noun()\n\ng) The Callback function allows the names that use the preposition + verb format, such as: `onCreate()`, `onDestroy()`, `toString()`.\n\n**Invalid example**:\n\n```kotlin\nfun type(): String\nfun Finished(): Boolean\nfun visible(boolean)\nfun DRAW()\nfun KeyListener(Listener)\n```\n\n**Valid example**:\n\n```kotlin\nfun getType(): String\nfun isFinished(): Boolean\nfun setVisible(boolean)\nfun draw()\nfun addKeyListener(Listener)\n```\n\n2.\tAn underscore (`_`) can be included in the JUnit test function name and should be used as a separator. Each logical part is denoted in `lowerCamelCase`, for example, a typical pattern of using underscore: `pop_emptyStack`.\n<!-- =============================================================================== -->\n### <a name=\"c1.5\"></a> 1.5 Constants\nThis section describes the general rules for naming constraints.\n### <a name=\"r1.5.1\"></a> 1.5.1 Using UPPER case and underscore characters in a constraint name\nConstant names should be in UPPER case, words separated by underscore. The general constant naming conventions are listed below:\n1. Constants are attributes created with the `const` keyword or top-level/`val` local variables of an object that holds immutable data. In most cases, constants can be identified as a `const val` property from the `object`/`companion object`/file top level. These variables contain fixed constant values that typically should never be changed by programmers. This includes basic types, strings, immutable types, and immutable collections of immutable types. The value is not constant for the object, which state can be changed.\n2. Constant names should contain only uppercase letters separated by an underscores. They should have a val or const val modifier to make them final explicitly. In most cases, if you need to specify a constant value, then you need to create it with the \"const val\" modifier. Note that not all `val` variables are constants.\n3. Objects with immutable content, such as `Logger` and `Lock`, can be in uppercase as constants or have camel case as regular variables.\n4. Use meaningful constants instead of `magic numbers`. SQL or logging strings should not be treated as magic numbers, nor should they be defined as string constants.\nMagic constants, such as `NUM_FIVE = 5` or `NUM_5 = 5` should not be treated as constants. This is because mistakes will easily be made if they are changed to `NUM_5 = 50` or 55.\nThese constants typically represent business logic values, such as measures, capacity, scope, location, tax rate, promotional discounts, and power base multiples in algorithms.\nYou can avoid using magic numbers with the following method:\n- Using library functions and APIs. For example, instead of checking that `size == 0`, use `isEmpty()` function. To work with `time`, use built-ins from `java.time API`.\n- Enumerations can be used to name patterns. Refer to [Recommended usage scenario for enumeration in 3.9](#c3.9).\n\n**Invalid example**:\n\n```kotlin\nvar int MAXUSERNUM = 200;\nval String sL = \"Launcher\";\n```\n\n**Valid example**:\n\n```kotlin\nconst val int MAX_USER_NUM = 200;\nconst val String APPLICATION_NAME = \"Launcher\";\n```\n\n<!-- =============================================================================== -->\n### <a name=\"c1.6\"></a> 1.6 Non-constant fields (variables)\nThis section describes the general rules for naming variables.\n### <a name=\"r1.6.1\"></a> 1.6.1 Non-constant field name\nNon-constant field names should use camel case and start with a lowercase letter.\nA local variable cannot be treated as constant even if it is final and immutable. Therefore, it should not use the preceding rules. Names of collection type variables (sets, lists, etc.) should contain plural nouns.\nFor example: `var namesList: List<String>`\n\nNames of non-constant variables should use `lowerCamelCase`. The name of the final immutable field used to store the singleton object can use the same camel case notation.\n\n**Invalid example**:\n```kotlin\ncustomername: String\nuser: List<String> = listof()\n```\n\n**Valid example**:\n```kotlin\nvar customerName: String\nval users: List<String> = listOf();\nval mutableCollection: MutableSet<String> = HashSet()\n```\n\n### <a name=\"r1.6.2\"></a> 1.6.2 Boolean variable names with negative meaning\n\nAvoid using Boolean variable names with a negative meaning. When using a logical operator and name with a negative meaning, the code may be difficult to understand, which is referred to as the \"double negative\".\nFor instance, it is not easy to understand the meaning of !isNotError.\nThe JavaBeans specification automatically generates isXxx() getters for attributes of Boolean classes.\nHowever, not all methods returning Boolean type have this notation.\nFor Boolean local variables or methods, it is highly recommended that you add non-meaningful prefixes, including is (commonly used by JavaBeans), has, can, should, and must. Modern integrated development environments (IDEs) such as Intellij are already capable of doing this for you when you generate getters in Java. For Kotlin, this process is even more straightforward as everything is on the byte-code level under the hood.\n\n**Invalid example**:\n```kotlin\nval isNoError: Boolean\nval isNotFound: Boolean\nfun empty()\nfun next();\n```\n\n**Valid example**:\n```kotlin\nval isError: Boolean\nval isFound: Boolean\nval hasLicense: Boolean\nval canEvaluate: Boolean\nval shouldAbort: Boolean\nfun isEmpty()\nfun hasNext()\n```\n# <a name=\"c2\"></a> 2. Comments\n\nThe best practice is to begin your code with a summary, which can be one sentence.\nTry to balance between writing no comments at all and obvious commentary statements for each line of code.\nComments should be accurately and clearly expressed, without repeating the name of the class, interface, or method.\nComments are not a solution to the wrong code. Instead, you should fix the code as soon as you notice an issue or plan to fix it (by entering a TODO comment, including a Jira number).\nComments should accurately reflect the code's design ideas and logic and further describe its business logic.\nAs a result, other programmers will be able to save time when trying to understand the code.\nImagine that you are writing the comments to help yourself to understand the original ideas behind the code in the future.\n\n### <a name=\"c2.1\"></a> 2.1 General form of Kdoc\n\nKDoc is a combination of JavaDoc's block tags syntax (extended to support specific constructions of Kotlin) and Markdown's inline markup.\nThe basic format of KDoc is shown in the following example:\n\n```kotlin\n /**\n * There are multiple lines of KDoc text,\n * Other ...\n */\nfun method(arg: String) {\n    // ...\n}\n```\n\nIt is also shown in the following single-line form:\n\n```kotlin\n /** Short form of KDoc. */\n```\nUse a single-line form when you store the entire KDoc block in one line (and there is no KDoc mark @XXX). For detailed instructions on how to use KDoc, refer to [Official Document](https://docs.oracle.com/en/Kotlin/Kotlinse/11/tools/KDoc.html).\n\n#### <a name=\"r2.1.1\"></a> 2.1.1 Using KDoc for the public, protected, or internal code elements\n\nAt a minimum, KDoc should be used for every public, protected, or internal decorated class, interface, enumeration, method, and member field (property).\nOther code blocks can also have KDocs if needed.\nInstead of using comments or KDocs before properties in the primary constructor of a class - use `@property` tag in a KDoc of a class.\nAll properties of the primary constructor should also be documented in a KDoc with a `@property` tag.\n\n\n**Incorrect example:**\n```kotlin\n/**\n * Class description\n */\nclass Example(\n /**\n  * property description\n  */\n  val foo: Foo,\n  // another property description\n  val bar: Bar\n)\n```\n\n**Correct example:**\n```kotlin\n/**\n * Class description\n * @property foo property description\n * @property bar another property description\n */\nclass Example(\n  val foo: Foo,\n  val bar: Bar\n)\n```\n- Don't use Kdoc comments inside code blocks as block comments\n\n**Incorrect Example:**\n\n```kotlin\nclass Example {\n  fun doGood() {\n    /**\n     * wrong place for kdoc\n     */\n    1 + 2\n  }\n}\n```\n\n**Correct Example:**\n\n```kotlin\nclass Example {\n  fun doGood() {\n    /*\n     * right place for block comment\n    */\n    1 + 2\n  }\n}\n```\n\n**Exceptions:**\n\n* For setters/getters of properties, obvious comments (like `this getter returns field`) are optional. Note that Kotlin generates simple `get/set` methods under the hood.\n\n* It is optional to add comments for simple one-line methods, such as shown in the example below:\n```kotlin\nval isEmpty: Boolean\n    get() = this.size == 0\n```\n\nor\n\n```kotlin\nfun isEmptyList(list: List<String>) = list.size == 0\n```\n\n**Note:** You can skip KDocs for a method's override if it is almost the same as the superclass method.\n\n#### <a name=\"r2.1.2\"></a> 2.1.2 Describing methods that have arguments, a return value, or can throw an exception in the KDoc block\n\nWhen the method has such details as arguments, return value, or can throw exceptions, it must be described in the KDoc block (with @param, @return, @throws, etc.).\n\n**Valid examples:**\n\n ```kotlin\n/**\n * This is the short overview comment for the example interface.\n *     / * Add a blank line between the comment text and each KDoc tag underneath * /\n * @since 1.6\n */\n protected abstract class Sample {\n    /**\n     * This is a long comment with whitespace that should be split in\n     * comments on multiple lines if the line comment formatting is enabled.\n     *     / * Add a blank line between the comment text and each KDoc tag underneath * /\n     * @param fox A quick brown fox jumps over the lazy dog\n     * @return battle between fox and dog\n     */\n    protected abstract fun foo(Fox fox)\n     /**\n      * These possibilities include: Formatting of header comments\n      *     / * Add a blank line between the comment text and each KDoc tag underneath * /\n      * @return battle between fox and dog\n      * @throws ProblemException if lazy dog wins\n      */\n    protected fun bar() throws ProblemException {\n        // Some comments / * No need to add a blank line here * /\n        var aVar = ...\n\n        // Some comments  / * Add a blank line before the comment * /\n        fun doSome()\n    }\n }\n ```\n\n#### <a name=\"r2.1.3\"></a>2.1.3 Only one space between the Kdoc tag and content. Tags are arranged in the order.\n\nThere should be only one space between the Kdoc tag and content. Tags are arranged in the following order: @param, @return, and @throws.\n\nTherefore, Kdoc should contain the following:\n- Functional and technical description, explaining the principles, intentions, contracts, API, etc.\n- The function description and @tags (`implSpec`, `apiNote`, and `implNote`) require an empty line after them.\n- `@implSpec`: A specification related to API implementation, and it should let the implementer decide whether to override it.\n- `@apiNote`: Explain the API precautions, including whether to allow null and whether the method is thread-safe, as well as the algorithm complexity, input, and output range, exceptions, etc.\n- `@implNote`: A note related to API implementation, which implementers should keep in mind.\n- One empty line, followed by regular `@param`, `@return`, `@throws`, and other comments.\n- The conventional standard \"block labels\" are arranged in the following order: `@param`, `@return`, `@throws`.\nKdoc should not contain:\n- Empty descriptions in tag blocks. It is better not to write Kdoc than waste code line space.\n- There should be no empty lines between the method/class declaration and the end of Kdoc (`*/` symbols).\n- `@author` tag. It doesn't matter who originally created a class when you can use `git blame` or VCS of your choice to look through the changes history.\nImportant notes:\n- KDoc does not support the `@deprecated` tag. Instead, use the `@Deprecated` annotation.\n- The `@since` tag should be used for versions only. Do not use dates in `@since` tag, it's confusing and less accurate.\n\nIf a tag block cannot be described in one line, indent the content of the new line by *four spaces* from the `@` position to achieve alignment (`@` counts as one + three spaces).\n\n**Exception:**\n\nWhen the descriptive text in a tag block is too long to wrap, you can indent the alignment with the descriptive text in the last line. The descriptive text of multiple tags does not need to be aligned.\nSee [3.8 Horizontal space](#c3.8).\n\nIn Kotlin, compared to Java, you can put several classes inside one file, so each class should have a Kdoc formatted comment (as stated in rule 2.1).\nThis comment should contain @since tag. The right style is to write the application version when its functionality is released. It should be entered after the `@since` tag.\n\n**Examples:**\n\n```kotlin\n/**\n * Description of functionality\n *\n * @since 1.6\n */\n```\n\nOther KDoc tags (such as @param type parameters and @see.) can be added as follows:\n```kotlin\n/**\n * Description of functionality\n *\n * @apiNote: Important information about API\n *\n * @since 1.6\n */\n```\n\n### <a name=\"c2.2\"></a> 2.2 Adding comments on the file header\n\nThis section describes the general rules of adding comments on the file header.\n\n### <a name=\"r2.2.1\"></a> 2.2.1 Formatting of comments in the file header\n\nComments on the file header should be placed before the package name and imports. If you need to add more content to the comment, subsequently add it in the same format.\n\nComments on the file header must include copyright information, without the creation date and author's name (use VCS for history management).\nAlso, describe the content inside files that contain multiple or no classes.\n\nThe following examples for Huawei describe the format of the *copyright license*: \\\nChinese version: `版权所有 (c) 华为技术有限公司 2012-2020` \\\nEnglish version: `Copyright (c) Huawei Technologies Co., Ltd. 2012-2020. All rights reserved.`\n`2012` and `2020` are the years the file was first created and the current year, respectively.\n\nDo not place **release notes** in header, use VCS to keep track of changes in file. Notable changes can be marked in individual KDocs using `@since` tag with version.\n\nInvalid example:\n```kotlin\n/**\n * Release notes:\n * 2019-10-11: added class Foo\n */\n\nclass Foo\n```\n\nValid example:\n```kotlin\n/**\n * @since 2.4.0\n */\nclass Foo\n```\n\n- The **copyright statement** can use your company's subsidiaries, as shown in the below examples: \\\nChinese version: `版权所有 (c) 海思半导体 2012-2020` \\\nEnglish version: `Copyright (c) Hisilicon Technologies Co., Ltd. 2012-2020. All rights reserved.`\n\n- The copyright information should not be written in KDoc style or use single-line comments. It must start from the beginning of the file.\nThe following example is a copyright statement for Huawei, without other functional comments:\n\n```kotlin\n/*\n * Copyright (c) Huawei Technologies Co., Ltd. 2012-2020. All rights reserved.\n */\n```\n\nThe following factors should be considered when writing the file header or comments for top-level classes:\n- File header comments must start from the top of the file. If it is a top-level file comment, there should be a blank line after the last Kdoc `*/` symbol. If it is a comment for a top-level class, the class declaration should start immediately without using a newline.\n- Maintain a unified format. The specific format can be formulated by the project (for example, if you use an existing opensource project), and you need to follow it.\n- A top-level file-Kdoc must include a copyright and functional description, especially if there is more than one top-level class.\n- Do not include empty comment blocks. If there is no content after the option `@apiNote`, the entire tag block should be deleted.\n- The industry practice is not to include historical information in the comments. The corresponding history can be found in VCS (git, svn, etc.). Therefore, it is not recommended to include historical data in the comments of the Kotlin source code.\n\n### <a name=\"c2.3\"></a> 2.3 Comments on the function header\n\nComments on the function header are placed above function declarations or definitions. A newline should not exist between a function declaration and its Kdoc. Use the preceding <<c2.1,KDoc>> style rules.\n\nAs stated in Chapter 1, the function name should reflect its functionality as much as possible. Therefore, in the Kdoc, try to describe the functionality that is not mentioned in the function name.\nAvoid unnecessary comments on dummy coding.\n\nThe function header comment's content is optional, but not limited to function description, return value, performance constraints, usage, memory conventions, algorithm implementation, reentrant requirements, etc.\n\n### <a name=\"c2.4\"></a> 2.4 Code comments\n\nThis section describes the general rules of adding code comments.\n\n#### <a name=\"r2.4.1\"></a> 2.4.1 Add a blank line between the body of the comment and Kdoc tag-blocks.\n\nIt is a good practice to add a blank line between the body of the comment and Kdoc tag-blocks. Also, consider the following rules:\n- There must be one space between the comment character and the content of the comment.\n- There must be a newline between a Kdoc and the presiding code.\n- An empty line should not exist between a Kdoc and the code it is describing. You do not need to add a blank line before the first comment in a particular namespace (code block) (for example, between the function declaration and first comment in a function body).\n\n**Valid Examples:**\n\n```kotlin\n/**\n * This is the short overview comment for the example interface.\n *\n * @since 1.6\n */\n public interface Example {\n    // Some comments  /* Since it is the first member definition in this code block, there is no need to add a blank line here */\n    val aField: String = ...\n                     /* Add a blank line above the comment */\n    // Some comments\n    val bField: String = ...\n                      /* Add a blank line above the comment */\n    /**\n     * This is a long comment with whitespace that should be split in\n     * multiple line comments in case the line comment formatting is enabled.\n     *                /* blank line between description and Kdoc tag */\n     * @param fox A quick brown fox jumps over the lazy dog\n     * @return the rounds of battle of fox and dog\n     */\n    fun foo(Fox fox)\n                      /* Add a blank line above the comment */\n     /**\n      * These possibilities include: Formatting of header comments\n      *\n      * @return the rounds of battle of fox and dog\n      * @throws ProblemException if lazy dog wins\n      */\n    fun bar() throws ProblemException {\n        // Some comments  /* Since it is the first member definition in this range, there is no need to add a blank line here */\n        var aVar = ...\n\n        // Some comments  /* Add a blank line above the comment */\n        fun doSome()\n    }\n }\n```\n\n- Leave one single space between the comment on the right side of the code and the code.\nIf you use conditional comments in the `if-else-if` scenario, put the comments inside the `else-if` branch or in the conditional block, but not before the `else-if`. This makes the code more understandable.\nWhen the if-block is used with curly braces, the comment should be placed on the next line after opening the curly braces.\nCompared to Java, the `if` statement in Kotlin statements returns a value. For this reason, a comment block can describe a whole `if-statement`.\n\n**Valid examples:**\n\n```kotlin\n\nval foo = 100  // right-side comment\nval bar = 200  /* right-side comment */\n\n// general comment for the value and whole if-else condition\nval someVal = if (nr % 15 == 0) {\n    // when nr is a multiple of both 3 and 5\n    println(\"fizzbuzz\")\n} else if (nr % 3 == 0) {\n    // when nr is a multiple of 3, but not 5\n    // We print \"fizz\", only.\n    println(\"fizz\")\n} else if (nr % 5 == 0) {\n    // when nr is a multiple of 5, but not 3\n    // we print \"buzz\" only.\n    println(\"buzz\")\n} else {\n    // otherwise, we print the number.\n    println(x)\n}\n```\n\n- Start all comments (including KDoc) with a space after the first symbol (`//`, `/*`, `/**` and `*`)\n\n**Valid example:**\n\n```kotlin\nval x = 0  // this is a comment\n```\n\n#### <a name=\"r2.4.2\"></a> 2.4.2 Do not comment on unused code blocks\n\nDo not comment on unused code blocks, including imports. Delete these code blocks immediately.\nA code is not used to store history. Git, svn, or other VCS tools should be used for this purpose.\nUnused imports increase the coupling of the code and are not conducive to maintenance. The commented out code cannot be appropriately maintained.\nIn an attempt to reuse the code, there is a high probability that you will introduce defects that are easily missed.\nThe correct approach is to delete the unnecessary code directly and immediately when it is not used anymore.\nIf you need the code again, consider porting or rewriting it as changes could have occurred since you first commented on the code.\n\n#### <a name=\"r2.4.3\"></a>2.4.3 Code delivered to the client should not contain TODO/FIXME comments\n\nThe code officially delivered to the client typically should not contain TODO/FIXME comments.\n`TODO` comments are typically used to describe modification points that need to be improved and added. For example, refactoring FIXME comments are typically used to describe known defects and bugs that will be subsequently fixed and are not critical for an application.\nThey should all have a unified style to facilitate unified text search processing.\n\n**Example:**\n\n```kotlin\n// TODO(<author-name>): Jira-XXX - support new json format\n// FIXME: Jira-XXX - fix NPE in this code block\n```\n\nAt a version development stage, these annotations can be used to highlight the issues in the code, but all of them should be fixed before a new product version is released.\n# <a name=\"c3\"></a>3. General formatting (typesetting)\n<!-- =============================================================================== -->\n### <a name=\"c3.1\"></a> 3.1 File-related rules\nThis section describes the rules related to using files in your code.\n#### <a name=\"r3.1.1\"></a> 3.1.1 Avoid files that are too long\n\nIf the file is too long and complicated, it should be split into smaller files, functions, or modules. Files should not exceed 2000 lines (non-empty and non-commented lines).\nIt is recommended to horizontally or vertically split the file according to responsibilities or hierarchy of its parts.\nThe only exception to this rule is code generation - the auto-generated files that are not manually modified can be longer.\n\n#### <a name=\"r3.1.2\"></a> 3.1.2 Code blocks in the source file should be separated by one blank line\nA source file contains code blocks in the following order: copyright, package name, imports, and top-level classes. They should be separated by one blank line.\n\na) Code blocks should be in the following order:\n1.\tKdoc for licensed or copyrighted files\n2.\t`@file` annotation\n3.\tPackage name\n4.\tImport statements\n5.\tTop-class header and top-function header comments\n6.\tTop-level classes or functions\n\nb) Each of the preceding code blocks should be separated by a blank line.\n\nc) Import statements are alphabetically arranged, without using line breaks and wildcards ( wildcard imports - `*`).\n\nd) **Recommendation**: One `.kt` source file should contain only one class declaration, and its name should match the filename\n\ne) Avoid empty files that do not contain the code or contain only imports/comments/package name\n\nf) Unused imports should be removed\n#### <a name=\"r3.1.3\"></a> 3.1.3 Import statements order\n\nFrom top to bottom, the order is the following:\n1. Android\n2. Imports of packages used internally in your organization\n3. Imports from other non-core dependencies\n4. Java core packages\n5. kotlin stdlib\n\nEach category should be alphabetically arranged. Each group should be separated by a blank line. This style is compatible with  [Android import order](https://source.android.com/setup/contribute/code-style#order-import-statements).\n\n**Valid example**:\n```kotlin\nimport android.* // android\nimport androidx.* // android\nimport com.android.* // android\n\nimport com.your.company.* // your company's libs\nimport your.company.* // your company's libs\n\nimport com.fasterxml.jackson.databind.ObjectMapper // other third-party dependencies\nimport org.junit.jupiter.api.Assertions\n\nimport java.io.IOException // java core packages\nimport java.net.URL\n\nimport kotlin.system.exitProcess  // kotlin standard library\nimport kotlinx.coroutines.*  // official kotlin extension library\n```\n\n#### <a name=\"r3.1.4\"></a> 3.1.4 Order of declaration parts of class-like code structures\nThe declaration parts of class-like code structures (class, interface, etc.) should be in the following order: compile-time constants (for objects), class properties, late-init class properties, init-blocks, constructors, public methods, internal methods, protected methods, private methods, and companion object. Blank lines should separate their declaration.\nNotes:\n1.\tThere should be no blank lines between properties with the following **exceptions**: when there is a comment before a property on a separate line or annotations on a separate line.\n2.\tProperties with comments/Kdoc should be separated by a newline before the comment/Kdoc.\n3.\tEnum entries and constant properties (`const val`) in companion objects should be alphabetically arranged.\n\nThe declaration part of a class or interface should be in the following order:\n- Compile-time constants (for objects)\n- Properties\n- Late-init class properties\n- Init-blocks\n- Constructors\n- Methods or nested classes. Put nested classes next to the code they are used by.\nIf the classes are meant to be used externally, and are not referenced inside the class, put them after the companion object.\n- Companion object\n\n**Exception:**\nAll variants of a `private val` logger should be placed at the beginning of the class (`private val log`, `LOG`, `logger`, etc.).\n\n#### <a name=\"r3.1.5\"></a> 3.1.5 Order of declaration of top-level code structures\nKotlin allows several top-level declaration types: classes, objects, interfaces, properties and functions.\nWhen declaring more than one class or zero classes (e.g. only functions), as per rule [2.2.1](#r2.2.1), you should document the whole file in the header KDoc.\nWhen declaring top-level structures, keep the following order:\n1. Top-level constants and properties (following same order as properties inside a class: `const val`,`val`, `lateinit var`, `var`)\n2. typealiases (grouped by their visibility modifiers)\n2. Interfaces, classes and objects (grouped by their visibility modifiers)\n3. Extension functions\n4. Other functions\n\n**Note**:\nExtension functions shouldn't have receivers declared in the same file according to [rule 6.2.3](#r6.2.3)\n\nValid example:\n```kotlin\npackage com.saveourtool.diktat.example\n\nconst val CONSTANT = 42\n\nval topLevelProperty = \"String constant\"\n\ninternal typealias ExamplesHandler = (IExample) -> Unit\n\ninterface IExample\n\nclass Example : IExample\n\nprivate class Internal\n\nfun Other.asExample(): Example { /* ... */ }\n\nprivate fun Other.asInternal(): Internal { /* ... */ }\n\nfun doStuff() { /* ... */ }\n```\n\n**Note**:\nkotlin scripts (.kts) allow arbitrary code to be placed on the top level. When writing kotlin scripts, you should first declare all properties, classes\nand functions. Only then you should execute functions on top level. It is still recommended wrapping logic inside functions and avoid using top-level statements\nfor function calls or wrapping blocks of code in top-level scope functions like `run`.\n\nExample:\n```kotlin\n/* class declarations */\n/* function declarations */\nrun {\n    // call functions here\n}\n```\n\n<!-- =============================================================================== -->\n### <a name=\"c3.2\"></a> 3.2 Braces\nThis section describes the general rules of using braces in your code.\n#### <a name=\"r3.2.1\"></a> 3.2.1 Using braces in conditional statements and loop blocks\n\nBraces should always be used in `if`, `else`, `for`, `do`, and `while` statements, even if the program body is empty or contains only one statement. In special Kotlin `when` statements, you do not need to use braces for single-line statements.\n\n**Valid example:**\n\n```kotlin\nwhen (node.elementType) {\n    FILE -> {\n        checkTopLevelDoc(node)\n        checkSomething()\n     }\n    CLASS -> checkClassElements(node)\n}\n```\n**Exception:** The only exception is ternary operator in Kotlin (a single line `if () <> else <>` )\n\n**Invalid example:**\n\n```kotlin\nval value = if (string.isEmpty())  // WRONG!\n                0\n            else\n                1\n```\n\n**Valid example**:\n\n```kotlin\nval value = if (string.isEmpty()) 0 else 1  // Okay\n```\n\n```kotlin\nif (condition) {\n    println(\"test\")\n} else {\n    println(0)\n}\n```\n\n#### <a name=\"r3.2.2\"></a> 3.2.2  Opening braces are placed at the end of the line in *non-empty* blocks and block structures\nFor *non-empty* blocks and block structures, the opening brace is placed at the end of the line.\nFollow the K&R style (1TBS or OTBS) for *non-empty* code blocks with braces:\n- The opening brace and first line of the code block are on the same line.\n- The closing brace is on its own new line.\n- The closing brace can be followed by a newline character. The only exceptions are `else`, `finally`, and `while` (from `do-while` statement), or `catch` keywords.\nThese keywords should not be split from the closing brace by a newline character.\n\n**Exception cases**:\n\n1) For lambdas, there is no need to put a newline character after the first (function-related) opening brace. A newline character should appear only after an arrow (`->`) (see [point 5 of Rule 3.6.2](#r3.6.2)).\n\n```kotlin\narg.map { value ->\n    foo(value)\n}\n```\n\n2) for `else`/`catch`/`finally`/`while` (from `do-while` statement) keywords closing brace should stay on the same line:\n ```kotlin\ndo {\n    if (true) {\n        x++\n    } else {\n        x--\n    }\n} while (x > 0)\n```\n\n**Valid example:**\n\n ```kotlin\n        return arg.map { value ->\n            while (condition()) {\n                method()\n            }\n            value\n        }\n\n        return MyClass() {\n            @Override\n              fun method() {\n                if (condition()) {\n                    try {\n                        something()\n                    } catch (e: ProblemException) {\n                        recover()\n                    }\n                } else if (otherCondition()) {\n                    somethingElse()\n                } else {\n                    lastThing()\n                }\n            }\n        }\n ```\n\n<!-- =============================================================================== -->\n### <a name=\"c3.3\"></a> 3.3 Indentation\n\nOnly spaces are permitted for indentation, and each indentation should equal `four spaces` (tabs are not permitted).\nIf you prefer using tabs, simply configure them to change to spaces in your IDE automatically.\nThese code blocks should be indented if they are placed on the new line, and the following conditions are met:\n-\tThe code block is placed immediately after an opening brace.\n-\tThe code block is placed after each operator, including the assignment operator (`+`/`-`/`&&`/`=`/etc.)\n-\tThe code block is a call chain of methods:\n```kotlin\nsomeObject\n    .map()\n    .filter()\n```\n-  The code block is placed immediately after the opening parenthesis.\n-  The code block is placed immediately after an arrow in lambda:\n\n ```kotlin\narg.map { value ->\n    foo(value)\n}\n```\n\n**Exceptions**:\n1.\tArgument lists: \\\na) Eight spaces are used to indent argument lists (both in declarations and at call sites). \\\nb) Arguments in argument lists can be aligned if they are on different lines.\n\n2.\tEight spaces are used if there is a newline after any binary operator.\n\n3.\tEight spaces are used for functional-like styles when the newline is placed before the dot.\n\n4.\tSupertype lists: \\\na) Four spaces are used if the colon before the supertype list is on a new line. \\\nb) Four spaces are used before each supertype, and eight spaces are used if the colon is on a new line.\n\n**Note:** there should be an indentation after all statements such as `if`, `for`, etc. However, according to this code style, such statements require braces.\n\n```kotlin\nif (condition)\n    foo()\n```\n\n**Exceptions**:\n- When breaking the parameter list of a method/class constructor, it can be aligned with `8 spaces`. A parameter that was moved to a new line can be on the same level as the previous argument:\n\n```kotlin\nfun visit(\n        node: ASTNode,\n        autoCorrect: Boolean,\n        params: KtLint.ExperimentalParams,\n        emit: (offset: Int, errorMessage: String, canBeAutoCorrected: Boolean) -> Unit\n) {\n}\n```\n\n- Such operators as `+`/`-`/`*` can be indented with `8 spaces`:\n\n```kotlin\nval abcdef = \"my splitted\" +\n                \" string\"\n```\n\n- Opening and closing quotes in multiline string should have same indentation\n\n```kotlin\nlintMethod(\n            \"\"\"\n                    |val q = 1\n                    |\n            \"\"\".trimMargin()\n    )\n```\n\n- A list of supertypes should be indented with `4 spaces` if they are on different lines or with `8 spaces` if the leading colon is also on a separate line\n\n```kotlin\nclass A :\n    B()\n\nclass A\n    :\n        B()\n```\n\n<!-- =============================================================================== -->\n### <a name=\"c3.4\"></a> 3.4 Empty blocks\n\nAvoid empty blocks, and ensure braces start on a new line. An empty code block can be closed immediately on the same line and the next line. However, a newline is recommended between opening and closing braces `{}` (see the examples below.)\n\nGenerally, empty code blocks are prohibited; using them is considered a bad practice (especially for catch block).\nThey are appropriate for overridden functions, when the base class's functionality is not needed in the class-inheritor, for lambdas used as a function and for empty function in implementation of functional interface.\n```kotlin\noverride fun foo() {\n}\n```\n\n**Valid examples** (note once again that generally empty blocks are prohibited):\n\n```kotlin\nfun doNothing() {}\n\nfun doNothingElse() {\n}\n\nfun foo(bar: () -> Unit = {})\n```\n\n**Invalid examples:**\n```kotlin\ntry {\n  doSomething()\n} catch (e: Some) {}\n```\n\nUse the following valid code instead:\n```kotlin\ntry {\n   doSomething()\n} catch (e: Some) {\n}\n```\n\n<!-- =============================================================================== -->\n### <a name=\"c3.5\"></a> 3.5 Line length\n\nLine length should be less than 120 symbols. Otherwise, it should be split.\n\nIf `complex property` initializing is too long, It should be split into priorities: \\\n1. Logic Binary Expression (&&  ||) \\\n2. Comparison Binary Expression (> < == >= <= !=) \\\n3. Other types (Arithmetical and Bit operation) (+ - * / % >> << *= += -= /= %= ++ -- ! in !in etc)\n\n**Invalid example:**\n```kotlin\nval complexProperty = 1 + 2 + 3 + 4\n```\n**Valid example:**\n```kotlin\nval complexProperty = 1 + 2 +\n    3 + 4\n```\n\n**Invalid example:**\n```kotlin\nval complexProperty = (1 + 2 + 3 > 0) && ( 23 * 4 > 10 * 6)\n```\n**Valid example:**\n```kotlin\nval complexProperty = (1 + 2 + 3 > 0) &&\n    (23 * 4 > 10 * 6)\n```\n\nIf long line should be split in `Elvis Operator` (?:), it`s done like this\n\n**Invalid example:**\n```kotlin\nval value = first ?: second\n```\n**Valid example:**\n```kotlin\nval value = first\n    ?: second\n```\n\nIf long line in `Dot Qualified Expression` or `Safe Access Expression`, it`s done like this:\n\n**Invalid example:**\n```kotlin\nval value = This.Is.Very.Long.Dot.Qualified.Expression\n```\n**Valid example:**\n```kotlin\nval value = This.Is.Very.Long\n    .Dot.Qualified.Expression\n```\n\n**Invalid example:**\n```kotlin\nval value = This.Is?.Very?.Long?.Safe?.Access?.Expression\n```\n**Valid example:**\n```kotlin\nval value = This.Is?.Very?.Long\n    ?.Safe?.Access?.Expression\n```\n\nif `value arguments list` is too long, it also should be split:\n\n**Invalid example:**\n```kotlin\nval result1 = ManyParamInFunction(firstArgument, secondArgument, thirdArgument, fourthArgument, fifthArguments)\n```\n**Valid example:**\n```kotlin\nval result1 = ManyParamInFunction(firstArgument,\n secondArgument, thirdArgument, fourthArgument,\n fifthArguments)\n```\n\nIf `annotation` is too long, it also should be split:\n\n**Invalid example:**\n```kotlin\n@Query(value = \"select * from table where age = 10\", nativeQuery = true)\nfun foo() {}\n```\n**Valid example:**\n```kotlin\n@Query(\n    value = \"select * from table where age = 10\",\n    nativeQuery = true)\nfun foo() {}\n```\n\nLong one line `function` should be split:\n\n**Invalid example:**\n```kotlin\nfun foo() = goo().write(\"TooLong\")\n```\n**Valid example:**\n```kotlin\nfun foo() =\n    goo().write(\"TooLong\")\n```\n\nLong `binary expression` should be split into priorities: \\\n1. Logic Binary Expression (**&&**  **||**) \\\n2. Comparison Binary Expression (**>** **<** **==** **>=** **<=** **!=**) \\\n3. Other types (Arithmetical and Bit operation) (**+** **-** * **/** **%** **>>** **<<** **/*=** **+=** **-=** **/=** **%=** **++** **--** **!** **in** **!in** etc)\n\n**Invalid example:**\n```kotlin\nif (( x >  100) || y < 100 && !isFoo()) {}\n```\n\n**Valid example:**\n```kotlin\nif (( x >  100) ||\n    y < 100 && !isFoo()) {}\n```\n\n`String template` also can be split in white space in string text\n\n**Invalid example:**\n```kotlin\nval nameString = \"This is very long string template\"\n```\n\n**Valid example:**\n```kotlin\nval nameString = \"This is very long\" +\n        \" string template\"\n```\n\nLong `Lambda argument` should be split:\n\n**Invalid example:**\n```kotlin\nval variable = a?.filter { it.elementType == true } ?: null\n```\n\n**Valid example:**\n```kotlin\nval variable = a?.filter {\n    it.elementType == true\n} ?: null\n```\n\nLong one line `When Entry` should be split:\n\n**Invalid example:**\n```kotlin\nwhen(elem) {\n    true -> long.argument.whenEntry\n}\n```\n**Valid example:**\n```kotlin\nwhen(elem) {\n    true -> {\n        long.argument.whenEntry\n    }\n}\n```\n\nIf the examples above do not fit, but the line needs to be split and this in `property`, this is fixed like thisЖ\n\n**Invalid example:**\n```kotlin\nval element = veryLongNameFunction(firstParam)\n```\n**Valid example:**\n```kotlin\nval element =\n    varyLongNameFunction(firstParam)\n```\n\n`Eol comment` also can be split, but it depends on comment location.\nIf this comment is on the same line with code it should be on line before:\n\n**Invalid example:**\n```kotlin\nfun foo() {\n    val name = \"Nick\" // this comment is too long\n}\n```\n**Valid example:**\n```kotlin\nfun foo() {\n    // this comment is too long\n    val name = \"Nick\"\n}\n```\n\nBut if this comment is on new line - it should be split to several lines:\n\n**Invalid example:**\n```kotlin\n// This comment is too long. It should be on two lines.\nfun foo() {}\n```\n\n**Valid example:**\n```kotlin\n// This comment is too long.\n// It should be on two lines.\nfun foo() {}\n```\n\nThe international code style prohibits `non-Latin` (`non-ASCII`) symbols. (See [Identifiers](#r1.1.1)) However, if you still intend on using them, follow\nthe following convention:\n\n- One wide character occupies the width of two narrow characters.\nThe \"wide\" and \"narrow\" parts of a character are defined by its [east Asian width Unicode attribute](https://unicode.org/reports/tr11/).\nTypically, narrow characters are also called \"half-width\" characters.\nAll characters in the ASCII character set include letters (such as `a, A`), numbers (such as `0, 3`), and punctuation spaces (such as `,` , `{`), all of which are narrow characters.\nWide characters are also called \"full-width\" characters. Chinese characters (such as `中, 文`), Chinese punctuation (`，` , `；` ), full-width letters and numbers (such as `Ａ、３`) are \"full-width\" characters.\nEach one of these characters represents two narrow characters.\n\n- Any line that exceeds this limit (`120 narrow symbols`) should be wrapped, as described in the [Newline section](#c3.5).\n\n**Exceptions:**\n\n1.\tThe long URL or long JSON method reference in KDoc.\n2.\tThe `package` and `import` statements.\n3.\tThe command line in the comment, enabling it to be cut and pasted into the shell for use.\n\n<!-- =============================================================================== -->\n### <a name=\"c3.6\"></a> 3.6 Line breaks (newlines)\nThis section contains the rules and recommendations on using line breaks.\n#### <a name=\"r3.6.1\"></a> 3.6.1 Each line can have a maximum of one statement\nEach line can have a maximum of one code statement. This recommendation prohibits the use of code with `;` because it decreases code visibility.\n\n**Invalid example:**\n```kotlin\nval a = \"\"; val b = \"\"\n```\n\n**Valid example:**\n```kotlin\nval a = \"\"\nval b = \"\"\n```\n\n#### <a name=\"r3.6.2\"></a> 3.6.2 Rules for line-breaking\n\n1) Unlike Java, Kotlin allows you not to put a semicolon (`;`) after each statement separated by a newline character.\n    There should be no redundant semicolon at the end of the lines.\n\nWhen a newline character is needed to split the line, it should be placed after such operators as `&&`/`||`/`+`/etc. and all infix functions (for example, `xor`).\nHowever, the newline character should be placed before operators such as `.`, `?.`, `?:`, and `::`.\n\nNote that all comparison operators, such as `==`, `>`, `<`, should not be split.\n\n**Invalid example**:\n```kotlin\n     if (node !=\n             null && test != null) {}\n```\n\n**Valid example**:\n```kotlin\n         if (node != null &&\n                 test != null) {\n         }\n```\n\n**Note:** You need to follow the functional style, meaning each function call in a chain with `.` should start at a new line if the chain of functions contains more than one call:\n```kotlin\n  val value = otherValue!!\n          .map { x -> x }\n          .filter {\n              val a = true\n              true\n          }\n          .size\n```\n**Note:** The parser prohibits the separation of the `!!` operator from the value it is checking.\n\n**Exception**: If a functional chain is used inside the branches of a ternary operator, it does not need to be split with newlines.\n\n**Valid example**:\n```kotlin\nif (condition) list.map { foo(it) }.filter { bar(it) } else list.drop(1)\n```\n\n**Note:** If dot qualified expression is inside condition or passed as an argument - it should be replaced with new variable.\n\n**Invalid example**:\n```kotlin\n if (node.treeParent.treeParent?.treeParent.findChildByType(IDENTIFIER) != null) {}\n```\n\n**Valid example**:\n```kotlin\n        val grandIdentifier = node\n            .treeParent\n            .treeParent\n            ?.treeParent\n            .findChildByType(IDENTIFIER)\n        if (grandIdentifier != null) {}\n```\n**Second valid example**:\n```kotlin\n        val grandIdentifier = node.treeParent\n            .treeParent\n            ?.treeParent\n            .findChildByType(IDENTIFIER)\n        if (grandIdentifier != null) {}\n```\n\n2)\tNewlines should be placed after the assignment operator (`=`).\n3)\tIn function or class declarations, the name of a function or constructor should not be split by a newline from the opening brace `(`.\n    A brace should be placed immediately after the name without any spaces in declarations or at call sites.\n4)\tNewlines should be placed right after the comma (`,`).\n5)\tIf a lambda statement contains more than one line in its body, a newline should be placed after an arrow if the lambda statement has explicit parameters.\n    If it uses an implicit parameter (`it`), the newline character should be placed after the opening brace (`{`).\n    The following examples illustrate this rule:\n\n\n**Invalid example:**\n```kotlin\n    value.map { name -> foo()\n        bar()\n    }\n```\n\n**Valid example:**\n```kotlin\nvalue.map { name ->\n    foo()\n    bar()\n}\n\nval someValue = { node:String -> node }\n```\n\n6) When the function contains only a single expression, it can be written as [expression function](https://kotlinlang.org/docs/reference/functions.html#single-expression-functions).\n   The below example shows the style that should not be used.\n\nInstead of:\n```kotlin\noverride fun toString(): String { return \"hi\" }\n```\nuse:\n```kotlin\noverride fun toString() = \"hi\"\n```\n\n7)  If an argument list in a function declaration (including constructors) or function call contains more than two arguments, these arguments should be split by newlines in the following style.\n\n**Valid example:**\n ```kotlin\nclass Foo(val a: String,\n          b: String,\n          val c: String) {\n}\n\nfun foo(\n        a: String,\n        b: String,\n        c: String\n) {\n\n}\n ```\n\nIf and only if the first parameter is on the same line as an opening parenthesis, all parameters can be horizontally aligned by the first parameter.\nOtherwise, there should be a line break after an opening parenthesis.\n\nKotlin 1.4 introduced a trailing comma as an optional feature, so it is generally recommended to place all parameters on a separate line\nand append [trailing comma](https://kotlinlang.org/docs/reference/whatsnew14.html#trailing-comma).\nIt makes the resolving of merge conflicts easier.\n\n**Valid example:**\n ```kotlin\nfun foo(\n        a: String,\n        b: String,\n) {\n\n}\n ```\n\nsame should be done for function calls/constructor arguments/e.t.c\n\nKotlin supports trailing commas in the following cases:\n\nEnumerations\nValue arguments\nClass properties and parameters\nFunction value parameters\nParameters with optional type (including setters)\nIndexing suffix\nLambda parameters\nwhen entry\nCollection literals (in annotations)\nType arguments\nType parameters\nDestructuring declarations\n\n8) If the supertype list has more than two elements, they should be separated by newlines.\n\n**Valid example:**\n```kotlin\nclass MyFavouriteVeryLongClassHolder :\n    MyLongHolder<MyFavouriteVeryLongClass>(),\n    SomeOtherInterface,\n    AndAnotherOne { }\n```\n\n<!-- =============================================================================== -->\n### <a name=\"c3.7\"></a> 3.7 Using blank lines\n\nReduce unnecessary blank lines and maintain a compact code size. By reducing unnecessary blank lines, you can display more code on one screen, which improves code readability.\n- Blank lines should separate content based on relevance and should be placed between groups of fields, constructors, methods, nested classes, `init` blocks, and objects (see [3.1.2](#r3.1.2)).\n- Do not use more than one line inside methods, type definitions, and initialization expressions.\n- Generally, do not use more than two consecutive blank lines in a row.\n- Do not put newlines in the beginning or end of code blocks with curly braces.\n\n**Valid example:**\n```kotlin\nfun baz() {\n\n    doSomething()  // No need to add blank lines at the beginning and end of the code block\n    // ...\n\n}\n```\n\n<!-- =============================================================================== -->\n### <a name=\"c3.8\"></a> 3.8 Horizontal space\nThis section describes general rules and recommendations for using spaces in the code.\n#### <a name=\"r3.8.1\"></a> 3.8.1: Usage of whitespace for code separation\n\nFollow the recommendations below for using space to separate keywords:\n\n**Note:** These recommendations are for cases where symbols are located on the same line. However, in some cases, a line break could be used instead of a space.\n\n1.  Separate keywords (such as `if`, `when`, `for`) from the opening parenthesis with single whitespace.\n    The only exception is the `constructor` keyword, which should not be separated from the opening parenthesis.\n\n2.  Separate keywords like `else` or `try` from the opening brace (`{`) with single whitespace.\n    If `else` is used in a ternary-style statement without braces, there should be a single space between `else` and the statement after: `if (condition) foo() else bar()`\n\n3.  Use a **single** whitespace before all opening braces (`{`). The only exception is the passing of a lambda as a parameter inside parentheses:\n ```kotlin\n     private fun foo(a: (Int) -> Int, b: Int) {}\n     foo({x: Int -> x}, 5) // no space before '{'\n ```\n\n4.  Single whitespace should be placed on both sides of binary operators. This also applies to operator-like symbols.\n    For example:\n\n - A colon in generic structures with the `where` keyword:  `where T : Type`\n - Arrow in lambdas: `(str: String) -> str.length()`\n\n**Exceptions:**\n\n- Two colons (`::`) are written without spaces:\\\n  `Object::toString`\n- The dot separator (`.`) that stays on the same line with an object name:\\\n  `object.toString()`\n- Safe access modifiers `?.` and `!!` that stay on the same line with an object name:\\\n  `object?.toString()`\n- Operator `..` for creating ranges:\\\n  `1..100`\n\n5.  Use spaces after (`,`), (`:`), and (`;`), except when the symbol is at the end of the line.\n    However, note that this code style prohibits the use of (`;`) in the middle of a line ([see 3.3.2](#r3.2.2)).\n    There should be no whitespaces at the end of a line.\n    The only scenario where there should be no space after a colon is when the colon is used in the annotation to specify a use-site target (for example, `@param:JsonProperty`).\n    There should be no spaces before `,` , `:` and `;`.\n\n    **Exceptions** for spaces and colons:\n\n    - When `:` is used to separate a type and a supertype, including an anonymous object (after object keyword)\n    - When delegating to a superclass constructor or different constructor of the same class\n\n**Valid example:**\n```kotlin\n  abstract class Foo<out T : Any> : IFoo { }\n\n  class FooImpl : Foo() {\n      constructor(x: String) : this(x) { /*...*/ }\n\n      val x = object : IFoo { /*...*/ }\n  }\n```\n\n6. There should be *only one space* between the identifier and its type: `list: List<String>`\nIf the type is nullable, there should be no space before `?`.\n\n7. When using `[]` operator (`get/set`) there should be **no** spaces between identifier and `[` : `someList[0]`.\n\n8. There should be no space between a method or constructor name (both at declaration and at call site) and a parenthesis:\n   `foo() {}`. Note that this sub-rule is related only to spaces; the rules for whitespaces are described in [see 3.6.2](#r3.6.2).\n    This rule does not prohibit, for example, the following code:\n```kotlin\nfun foo\n(\n    a: String\n)\n```\n\n9. Never put a space after `(`, `[`, `<` (when used as a bracket in templates) or before `)`, `]`, `>` (when used as a bracket in templates).\n\n10. There should be no spaces between a prefix/postfix operator (like `!!` or `++`) and its operand.\n\n#### <a name=\"r3.8.2\"></a> 3.8.2: No spaces for horizontal alignment\n\n*Horizontal alignment* refers to aligning code blocks by adding space to the code. Horizontal alignment should not be used because:\n\n- When modifying code, it takes much time for new developers to format, support, and fix alignment issues.\n- Long identifier names will break the alignment and lead to less presentable code.\n- There are more disadvantages than advantages in alignment. To reduce maintenance costs, misalignment (???) is the best choice.\n\nRecommendation: Alignment only looks suitable for `enum class`, where it can be used in table format to improve code readability:\n```kotlin\nenum class Warnings(private val id: Int, private val canBeAutoCorrected: Boolean, private val warn: String) : Rule {\n    PACKAGE_NAME_MISSING         (1, true,  \"no package name declared in a file\"),\n    PACKAGE_NAME_INCORRECT_CASE  (2, true,  \"package name should be completely in a lower case\"),\n    PACKAGE_NAME_INCORRECT_PREFIX(3, false, \"package name should start from the company's domain\")\n    ;\n}\n```\n\n**Valid example:**\n ```kotlin\n private val nr: Int // no alignment, but looks fine\n private var color: Color // no alignment\n ```\n\n**Invalid example**:\n ```kotlin\n private val    nr: Int    // aligned comment with extra spaces\n private val color: Color  // alignment for a comment and alignment for identifier name\n ```\n\n<!-- =============================================================================== -->\n### <a name=\"c3.9\"></a> 3.9 Enumerations\nEnum values are separated by a comma and line break, with ';' placed on the new line.\n\n1) The comma and line break characters separate enum values. Put `;` on the new line:\n```kotlin\nenum class Warnings {\n    A,\n    B,\n    C,\n    ;\n}\n```\n\nThis will help to resolve conflicts and reduce the number of conflicts during merging pull requests.\nAlso, use [trailing comma](https://kotlinlang.org/docs/reference/whatsnew14.html#trailing-comma).\n\n2) If the enum is simple (no properties, methods, and comments inside), you can declare it in a single line:\n```kotlin\nenum class Suit { CLUBS, HEARTS, SPADES, DIAMONDS }\n```\n\n3) Enum classes take preference (if it is possible to use it). For example, instead of two boolean properties:\n\n```kotlin\nval isCelsius = true\nval isFahrenheit = false\n```\n\nuse enum class:\n\n```kotlin\nenum class TemperatureScale { CELSIUS, FAHRENHEIT }\n```\n\n- The variable value only changes within a fixed range and is defined with the enum type.\n- Avoid comparison with magic numbers of `-1, 0, and 1`; use enums instead.\n\n```kotlin\nenum class ComparisonResult {\n    ORDERED_ASCENDING,\n    ORDERED_SAME,\n    ORDERED_DESCENDING,\n    ;\n}\n```\n\n<!-- =============================================================================== -->\n### <a name=\"c3.10\"></a> 3.10 Variable declaration\nThis section describes rules for the declaration of variables.\n#### <a name=\"r3.10.1\"></a> 3.10.1 Declare one variable per line\n\nEach property or variable must be declared on a separate line.\n\n**Invalid example**:\n```kotlin\nval n1: Int; val n2: Int\n```\n\n#### <a name=\"r3.10.2\"></a> 3.10.2 Variables should be declared near the line where they are first used\nDeclare local variables close to the point where they are first used to minimize their scope. This will also increase the readability of the code.\nLocal variables are usually initialized during their declaration or immediately after.\nThe member fields of the class should be declared collectively (see [Rule 3.1.2](#r3.1.2) for details on the class structure).\n\n<!-- =============================================================================== -->\n### <a name=\"c3.11\"></a> 3.11 'When' expression\n\nThe `when` statement must have an 'else' branch unless the condition variable is enumerated or a sealed type.\nEach `when` statement should contain an `else` statement group, even if it does not contain any code.\n\n**Exception:** If 'when' statement of the `enum or sealed` type contains all enum values, there is no need to have an \"else\" branch.\nThe compiler can issue a warning when it is missing.\n\n<!-- =============================================================================== -->\n### <a name=\"c3.12\"></a> 3.12 Annotations\n\nEach annotation applied to a class, method or constructor should be placed on its own line. Consider the following examples:\n1. Annotations applied to the class, method or constructor are placed on separate lines (one annotation per line).\n\n**Valid example**:\n```kotlin\n@MustBeDocumented\n@CustomAnnotation\nfun getNameIfPresent() { /* ... */ }\n```\n\n2. A single annotation should be on the same line as the code it is annotating.\n\n**Valid example**:\n```kotlin\n@CustomAnnotation class Foo {}\n```\n\n3. Multiple annotations applied to a field or property can appear on the same line as the corresponding field.\n\n**Valid example**:\n```kotlin\n@MustBeDocumented @CustomAnnotation val loader: DataLoader\n```\n\n<!-- =============================================================================== -->\n### <a name=\"c3.13\"></a> 3.13 Block comments\n\nBlock comments should be placed at the same indentation level as the surrounding code. See examples below.\n\n**Valid example**:\n\n ```kotlin\nclass SomeClass {\n     /*\n      * This is\n      * okay\n      */\n      fun foo() {}\n}\n ```\n\n**Note**: Use `/*...*/` block comments to enable automatic formatting by IDEs.\n\n<!-- =============================================================================== -->\n### <a name=\"c3.14\"></a> 3.14 Modifiers and constant values\nThis section contains recommendations regarding modifiers and constant values.\n#### <a name=\"r3.14.1\"></a> 3.14.1 Declaration with multiple modifiers\nIf a declaration has multiple modifiers, always follow the proper sequence.\n**Valid sequence:**\n\n```kotlin\npublic / internal / protected / private\nexpect / actual\nfinal / open / abstract / sealed / const\nexternal\noverride\nlateinit\ntailrec\ncrossinline\nvararg\nsuspend\ninner\nout\nenum / annotation\ncompanion\ninline / noinline\nreified\ninfix\noperator\ndata\n```\n\n#### <a name=\"r3.14.2\"></a> 3.14.2: Separate long numerical values with an underscore\nAn underscore character should separate long numerical values.\n**Note:** Using underscores simplifies reading and helps to find errors in numeric constants.\n```kotlin\nval oneMillion = 1_000_000\nval creditCardNumber = 1234_5678_9012_3456L\nval socialSecurityNumber = 999_99_9999L\nval hexBytes = 0xFF_EC_DE_5E\nval bytes = 0b11010010_01101001_10010100_10010010\n```\n#### <a name=\"r3.14.3\"></a> 3.14.3: Magic number\nPrefer defining constants with clear names describing what the magic number means.\n**Valid example**:\n```kotlin\nclass Person() {\n    fun isAdult(age: Int): Boolean = age >= majority\n\n    companion object {\n        private const val majority = 18\n    }\n}\n```\n**Invalid example**:\n```kotlin\nclass Person() {\n    fun isAdult(age: Int): Boolean = age >= 18\n}\n```\n\n<!-- =============================================================================== -->\n### <a name=\"c3.15\"></a> 3.15 Strings\nThis section describes the general rules of using strings.\n\n#### <a name=\"r3.15.1\"></a> 3.15.1 Concatenation of Strings\nString concatenation is prohibited if the string can fit on one line. Use raw strings and string templates instead. Kotlin has significantly improved the use of Strings:\n[String templates](https://kotlinlang.org/docs/reference/basic-types.html#string-templates), [Raw strings](https://kotlinlang.org/docs/reference/basic-types.html#string-literals).\nTherefore, compared to using explicit concatenation, code looks much better when proper Kotlin strings are used for short lines, and you do not need to split them with newline characters.\n\n**Invalid example**:\n```kotlin\nval myStr = \"Super string\"\nval value = myStr + \" concatenated\"\n```\n\n**Valid example**:\n```kotlin\nval myStr = \"Super string\"\nval value = \"$myStr concatenated\"\n```\n\n#### <a name=\"r3.15.2\"></a> 3.15.2 String template format\n**Redundant curly braces in string templates**\n\nIf there is only one variable in a string template, there is no need to use such a template. Use this variable directly.\n**Invalid example**:\n```kotlin\nval someString = \"${myArgument} ${myArgument.foo()}\"\n```\n\n**Valid example**:\n```kotlin\nval someString = \"$myArgument ${myArgument.foo()}\"\n```\n\n**Redundant string template**\n\nIn case a string template contains only one variable - there is no need to use the string template. Use this variable directly.\n\n**Invalid example**:\n```kotlin\nval someString = \"$myArgument\"\n```\n\n**Valid example**:\n```kotlin\nval someString = myArgument\n```\n\n<!-- =============================================================================== -->\n### <a name=\"c3.16\"></a> 3.16 Conditional Statements\nThis section describes the general rules related to the сonditional statements.\n\n#### <a name=\"r3.16.1\"></a> 3.16.1 Collapsing redundant nested if-statements\nThe nested if-statements, when possible, should be collapsed into a single one\nby concatenating their conditions with the infix operator &&.\n\nThis improves the readability by reducing the number of the nested language constructs.\n\n#### Simple collapse\n\n**Invalid example**:\n```kotlin\nif (cond1) {\n    if (cond2) {\n        doSomething()\n    }\n}\n```\n\n**Valid example**:\n```kotlin\nif (cond1 && cond2) {\n    doSomething()\n}\n```\n\n#### Compound conditions\n\n**Invalid example**:\n```kotlin\nif (cond1) {\n    if (cond2 || cond3) {\n        doSomething()\n    }\n}\n```\n\n**Valid example**:\n```kotlin\nif (cond1 && (cond2 || cond3)) {\n    doSomething()\n}\n```\n#### <a name=\"r3.16.2\"></a> 3.16.2 Too complex conditions\nToo complex conditions should be simplified according to boolean algebra rules, if it is possible.\nThe following rules are considered when simplifying an expression:\n* boolean literals are removed (e.g. `foo() || false` -> `foo()`)\n* double negation is removed (e.g. `!(!a)` -> `a`)\n* expression with the same variable are simplified (e.g. `a && b && a` -> `a && b`)\n* remove expression from disjunction, if they are subset of other expression (e.g. `a || (a && b)` -> `a`)\n* remove expression from conjunction, if they are more broad than other expression (e.g. `a && (a || b)` -> `a`)\n* de Morgan's rule (negation is moved inside parentheses, i.e. `!(a || b)` -> `!a && !b`)\n\n**Valid example**\n```kotlin\nif (condition1 && condition2) {\n    foo()\n}\n```\n\n**Invalid example**\n```kotlin\nif (condition1 && condition2 && condition1) {\n    foo()\n}\n```\n# <a name=\"c4\"></a> 4. Variables and types\nThis section is dedicated to the rules and recommendations for using variables and types in your code.\n<!-- =============================================================================== -->\n### <a name=\"c4.1\"></a> 4.1 Variables\nThe rules of using variables are explained in the below topics.\n#### <a name=\"r4.1.1\"></a> 4.1.1 Do not use Float and Double types when accurate calculations are needed\nFloating-point numbers provide a good approximation over a wide range of values, but they cannot produce accurate results in some cases.\nBinary floating-point numbers are unsuitable for precise calculations because it is impossible to represent 0.1 or any other negative power of 10 in a `binary representation` with a finite length.\n\nThe following code example seems to be obvious:\n```kotlin\n    val myValue = 2.0 - 1.1\n    println(myValue)\n```\n\nHowever, it will print the following value: `0.8999999999999999`\n\nTherefore, for precise calculations (for example, in finance or exact sciences), using such types as `Int`, `Long`, `BigDecimal`are recommended.\nThe `BigDecimal` type should serve as a good choice.\n\n**Invalid example**:\nFloat values containing more than six or seven decimal numbers will be rounded.\n ```kotlin\n val eFloat = 2.7182818284f // Float, will be rounded to 2.7182817\n ```\n\n**Valid example**: (when precise calculations are needed):\n ```kotlin\n    val income = BigDecimal(\"2.0\")\n    val expense = BigDecimal(\"1.1\")\n    println(income.subtract(expense)) // you will obtain 0.9 here\n ```\n\n#### <a name=\"r4.1.2\"></a> 4.1.2: Comparing numeric float type values\nNumeric float type values should not be directly compared with the equality operator (==) or other methods, such as `compareTo()` and `equals()`. Since floating-point numbers involve precision problems in computer representation, it is better to use `BigDecimal` as recommended in [Rule 4.1.1](#r4.1.1) to make accurate computations and comparisons. The following code describes these problems.\n\n**Invalid example**:\n ```kotlin\nval f1 = 1.0f - 0.9f\nval f2 = 0.9f - 0.8f\nif (f1 == f2) {\n    println(\"Expected to enter here\")\n} else {\n    println(\"But this block will be reached\")\n}\n\nval flt1 = f1;\nval flt2 = f2;\nif (flt1.equals(flt2)) {\n    println(\"Expected to enter here\")\n} else {\n    println(\"But this block will be reached\")\n}\n ```\n\n**Valid example**:\n\n```kotlin\nval foo = 1.03f\nval bar = 0.42f\nif (abs(foo - bar) > 1e-6f) {\n    println(\"Ok\")\n} else {\n    println(\"Not\")\n}\n```\n\n#### <a name=\"r4.1.3\"></a> 4.1.3 Try to use 'val' instead of 'var' for variable declaration [SAY_NO_TO_VAR]\n\nVariables with the `val` modifier are immutable (read-only).\nUsing `val` variables instead of `var` variables increases code robustness and readability.\nThis is because `var` variables can be reassigned several times in the business logic.\nHowever, in some scenarios with loops or accumulators, only `var`s are permitted.\n\n<!-- =============================================================================== -->\n### <a name=\"c4.2\"></a> 4.2 Types\nThis section provides recommendations for using types.\n#### <a name=\"r4.2.1\"></a> 4.2.1: Use Contracts and smart cast as much as possible\n\nThe Kotlin compiler has introduced [Smart Casts](https://kotlinlang.org/docs/reference/typecasts.html#smart-casts) that help reduce the size of code.\n\n**Invalid example**:\n```kotlin\n    if (x is String) {\n        print((x as String).length) // x was already automatically cast to String - no need to use 'as' keyword here\n    }\n```\n\n**Valid example**:\n```kotlin\n    if (x is String) {\n        print(x.length) // x was already automatically cast to String - no need to use 'as' keyword here\n    }\n```\n\nAlso, Kotlin 1.3 introduced [Contracts](https://kotlinlang.org/docs/reference/whatsnew13.html#contracts) that provide enhanced logic for smart-cast.\nContracts are used and are very stable in `stdlib`, for example:\n\n\n```kotlin\nfun bar(x: String?) {\n    if (!x.isNullOrEmpty()) {\n        println(\"length of '$x' is ${x.length}\") // smartcasted to not-null\n    }\n}\n```\n\nSmart cast and contracts are a better choice because they reduce boilerplate code and features forced type conversion.\n\n**Invalid example**:\n```kotlin\nfun String?.isNotNull(): Boolean = this != null\n\nfun foo(s: String?) {\n    if (s.isNotNull()) s!!.length // No smartcast here and !! operator is used\n}\n```\n\n**Valid example**:\n```kotlin\nfun foo(s: String?) {\n    if (s.isNotNull()) s.length // We have used a method with contract from stdlib that helped compiler to execute smart cast\n}\n```\n\n#### <a name=\"r4.2.2\"></a> 4.2.2: Try to use type alias to represent types making code more readable\n\nType aliases provide alternative names for existing types.\nIf the type name is too long, you can replace it with a shorter name, which helps to shorten long generic types.\nFor example, code looks much more readable if you introduce a `typealias` instead of a long chain of nested generic types.\nWe recommend using a `typealias` if the type contains **more than two** nested generic types and is longer than **25 chars**.\n\n**Invalid example**:\n```kotlin\nval b: MutableMap<String, MutableList<String>>\n```\n\n**Valid example**:\n```kotlin\ntypealias FileTable = MutableMap<String, MutableList<String>>\nval b: FileTable\n```\n\nYou can also provide additional aliases for function (lambda-like) types:\n```kotlin\ntypealias MyHandler = (Int, String, Any) -> Unit\n\ntypealias Predicate<T> = (T) -> Boolean\n```\n\n<!-- =============================================================================== -->\n### <a name=\"c4.3\"></a> 4.3 Null safety and variable declarations\nKotlin is declared as a null-safe programming language. However, to achieve compatibility with Java, it still supports nullable types.\n\n#### <a name=\"r4.3.1\"></a> 4.3.1: Avoid declaring variables with nullable types, especially from Kotlin stdlib\nTo avoid `NullPointerException` and help the compiler prevent Null Pointer Exceptions, avoid using nullable types (with `?` symbol).\n\n**Invalid example**:\n```kotlin\nval a: Int? = 0\n```\n\n**Valid example**:\n```kotlin\nval a: Int = 0\n```\n\nNevertheless, when using Java libraries extensively, you have to use nullable types and enrich the code with `!!` and `?` symbols.\nAvoid using nullable types for Kotlin stdlib (declared in [official documentation](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.collections/)).\nTry to use initializers for empty collections. For example, if you want to initialize a list instead of `null`, use `emptyList()`.\n\n**Invalid example**:\n```kotlin\nval a: List<Int>? = null\n```\n\n**Valid example**:\n```kotlin\nval a: List<Int> = emptyList()\n```\n\n#### <a name=\"r4.3.2\"></a> 4.3.2: Variables of generic types should have an explicit type declaration\nLike in Java, classes in Kotlin may have type parameters. To create an instance of such a class, we typically need to provide type arguments:\n\n```kotlin\nval myVariable: Map<Int, String> = emptyMap<Int, String>()\n```\n\nHowever, the compiler can inherit type parameters from the r-value (value assigned to a variable). Therefore, it will not force users to declare the type explicitly.\nThese declarations are not recommended because programmers would need to find the return value and understand the variable type by looking at the method.\n\n**Invalid example**:\n```kotlin\nval myVariable = emptyMap<Int, String>()\n```\n\n**Valid example**:\n```kotlin\nval myVariable: Map<Int, String> = emptyMap()\n```\n\n#### <a name=\"r4.3.3\"></a> 4.3.3 Null-safety\n\nTry to avoid explicit null checks (explicit comparison with `null`)\nKotlin is declared as [Null-safe](https://kotlinlang.org/docs/reference/null-safety.html) language.\nHowever, Kotlin architects wanted Kotlin to be fully compatible with Java; that's why the `null` keyword was also introduced in Kotlin.\n\nThere are several code-structures that can be used in Kotlin to avoid null-checks. For example: `?:`,  `.let {}`, `.also {}`, e.t.c\n\n**Invalid example:**\n```kotlin\n// example 1\nvar myVar: Int? = null\nif (myVar == null) {\n    println(\"null\")\n    return\n}\n\n// example 2\nif (myVar != null) {\n    println(\"not null\")\n    return\n}\n\n// example 3\nval anotherVal = if (myVar != null) {\n                     println(\"not null\")\n                     1\n                 } else {\n                     2\n                 }\n// example 4\nif (myVar == null) {\n    println(\"null\")\n} else {\n    println(\"not null\")\n}\n```\n\n**Valid example:**\n```kotlin\n// example 1\nvar myVar: Int? = null\nmyVar?: run {\n    println(\"null\")\n    return\n}\n\n// example 2\nmyVar?.let {\n    println(\"not null\")\n    return\n}\n\n// example 3\nval anotherVal = myVar?.also {\n                     println(\"not null\")\n                     1\n                 } ?: 2\n\n// example 4\nmyVar?.let {\n    println(\"not null\")\n} ?: run { println(\"null\") }\n```\n\n**Exceptions:**\n\nIn the case of complex expressions, such as multiple `else-if` structures or long conditional statements, there is common sense to use explicit comparison with `null`.\n\n**Valid examples:**\n\n```kotlin\nif (myVar != null) {\n    println(\"not null\")\n} else if (anotherCondition) {\n    println(\"Other condition\")\n}\n```\n\n```kotlin\nif (myVar == null || otherValue == 5 && isValid) {}\n```\n\nPlease also note, that instead of using `require(a != null)` with a not null check - you should use a special Kotlin function called `requireNotNull(a)`.\n\n# <a name=\"c5\"></a> 5. Functions\nThis section describes the rules of using functions in your code.\n<!-- =============================================================================== -->\n### <a name=\"c5.1\"></a> 5.1 Function design\nDevelopers can write clean code by gaining knowledge of how to build design patterns and avoid code smells.\nYou should utilize this approach, along with functional style, when writing Kotlin code.\nThe concepts behind functional style are as follows:\nFunctions are the smallest unit of combinable and reusable code.\nThey should have clean logic, **high cohesion**, and **low coupling** to organize the code effectively.\nThe code in functions should be simple and not conceal the author's original intentions.\n\nAdditionally, it should have a clean abstraction, and control statements should be used straightforwardly.\nThe side effects (code that does not affect a function's return value but affects global/object instance variables) should not be used for state changes of an object.\nThe only exceptions to this are state machines.\n\nKotlin is [designed](https://www.slideshare.net/abreslav/whos-more-functional-kotlin-groovy-scala-or-java) to support and encourage functional programming, featuring the corresponding built-in mechanisms.\nAlso, it supports standard collections and sequences feature methods that enable functional programming (for example, `apply`, `with`, `let`, and `run`), Kotlin Higher-Order functions, function types, lambdas, and default function arguments.\nAs [previously discussed](#r4.1.3), Kotlin supports and encourages the use of immutable types, which in turn motivates programmers to write pure functions that avoid side effects and have a corresponding output for specific input.\nThe pipeline data flow for the pure function comprises a functional paradigm. It is easy to implement concurrent programming when you have chains of function calls, where each step features the following characteristics:\n1.\tSimplicity\n2.\tVerifiability\n3.\tTestability\n4.\tReplaceability\n5.\tPluggability\n6.\tExtensibility\n7.\tImmutable results\n\nThere can be only one side effect in this data stream, which can be placed only at the end of the execution queue.\n\n#### <a name=\"r5.1.1\"></a> 5.1.1 Avoid functions that are too long\n\nThe function should be displayable on one screen and only implement one certain logic.\nIf a function is too long, it often means complex and could be split or simplified. Functions should consist of 30 lines (non-empty and non-comment) in total.\n\n**Exception:** Some functions that implement complex algorithms may exceed 30 lines due to aggregation and comprehensiveness.\nLinter warnings for such functions **can be suppressed**.\n\nEven if a long function works well, new problems or bugs may appear due to the function's complex logic once it is modified by someone else.\nTherefore, it is recommended to split such functions into several separate and shorter functions that are easier to manage.\nThis approach will enable other programmers to read and modify the code properly.\n#### <a name=\"r5.1.2\"></a> 5.1.2 Avoid deep nesting of function code blocks, limiting to four levels\n\nThe nesting depth of a function's code block is the depth of mutual inclusion between the code control blocks in the function (for example: if, for, while, and when).\nEach nesting level will increase the amount of effort needed to read the code because you need to remember the current \"stack\" (for example, entering conditional statements and loops).\n**Exception:** The nesting levels of the lambda expressions, local classes, and anonymous classes in functions are calculated based on the innermost function. The nesting levels of enclosing methods are not accumulated.\nFunctional decomposition should be implemented to avoid confusion for the developer who reads the code.\nThis will help the reader switch between contexts.\n\n#### <a name=\"r5.1.3\"></a> 5.1.3 Avoid using nested functions\nNested functions create a more complex function context, thereby confusing readers.\nWith nested functions, the visibility context may not be evident to the code reader.\n\n**Invalid example**:\n```kotlin\nfun foo() {\n    fun nested():String {\n        return \"String from nested function\"\n    }\n    println(\"Nested Output: ${nested()}\")\n}\n```\n#### <a name=\"r5.1.4\"></a> 5.1.4 Negated function calls\nDon't use negated function calls if it can be replaced with negated version of this function\n\n**Invalid example**:\n```kotlin\nfun foo() {\n    val list = listOf(1, 2, 3)\n\n    if (!list.isEmpty()) {\n        // Some cool logic\n    }\n}\n```\n\n**Valid example**:\n```kotlin\nfun foo() {\n    val list = listOf(1, 2, 3)\n\n    if (list.isNotEmpty()) {\n        // Some cool logic\n    }\n}\n```\n\n<!-- =============================================================================== -->\n### <a name=\"c5.2\"></a> 5.2 Function arguments\nThe rules for using function arguments are described in the below topics.\n#### <a name=\"r5.2.1\"></a> 5.2.1 The lambda parameter of the function should be placed at the end of the argument list\n\nWith such notation, it is easier to use curly brackets, leading to better code readability.\n\n**Valid example**:\n```kotlin\n// declaration\nfun myFoo(someArg: Int, myLambda: () -> Unit) {\n// ...\n}\n\n// usage\nmyFoo(1) {\nprintln(\"hey\")\n}\n```\n\n#### <a name=\"r5.2.2\"></a> 5.2.2 Number of function parameters should be limited to five\n\nA long argument list is a [code smell](https://en.wikipedia.org/wiki/Code_smell) that leads to less reliable code.\nIt is recommended to reduce the number of parameters. Having **more than five** parameters leads to difficulties in maintenance and conflicts merging.\nIf parameter groups appear in different functions multiple times, these parameters are closely related and can be encapsulated into a single Data Class.\nIt is recommended that you use Data Classes and Maps to unify these function arguments.\n\n#### <a name=\"r5.2.3\"></a> 5.2.3 Use default values for function arguments instead of overloading them\nIn Java, default values for function arguments are prohibited. That is why the function should be overloaded when you need to create a function with fewer arguments.\nIn Kotlin, you can use default arguments instead.\n\n**Invalid example**:\n```kotlin\nprivate fun foo(arg: Int) {\n    // ...\n}\n\nprivate fun foo() {\n    // ...\n}\n```\n\n**Valid example**:\n```kotlin\n private fun foo(arg: Int = 0) {\n     // ...\n }\n```\n#### <a name=\"r5.2.4\"></a> 5.2.4 Synchronizing code inside asynchronous code\nTry to avoid using `runBlocking` in asynchronous code\n\n**Invalid example**:\n```kotlin\nGlobalScope.async {\n    runBlocking {\n        count++\n    }\n}\n```\n#### <a name=\"r5.2.5\"></a> 5.2.5 Long lambdas should have explicit parameters\nThe lambda without parameters shouldn't be too long.\nIf a lambda is too long, it can confuse the user. Lambda without parameters should consist of 10 lines (non-empty and non-comment) in total.\n\n#### <a name=\"r5.2.6\"></a> 5.2.6 Avoid using unnecessary, custom label\nExpressions with unnecessary, custom labels generally increase complexity and worsen the maintainability of the code.\n\n**Invalid example**:\n```kotlin\nrun lab@ {\n    list.forEach {\n        return@lab\n    }\n}\n```\n\n**Valid example**:\n```kotlin\nlist.forEachIndexed { index, i ->\n    return@forEachIndexed\n}\n\nlab@ for(i: Int in q) {\n    for (j: Int in q) {\n        println(i)\n        break@lab\n    }\n}\n```\n# <a name=\"c6\"></a> 6. Classes, interfaces, and extension functions\n<!-- =============================================================================== -->\n### <a name=\"c6.1\"></a> 6.1 Classes\nThis section describes the rules of denoting classes in your code.\n#### <a name=\"r6.1.1\"></a> 6.1.1  Denoting a class with a single constructor\nWhen a class has a single constructor, it should be defined as a primary constructor in the declaration of the class. If the class contains only one explicit constructor, it should be converted to a primary constructor.\n\n**Invalid example**:\n```kotlin\nclass Test {\n    var a: Int\n    constructor(a: Int) {\n        this.a = a\n    }\n}\n```\n\n**Valid example**:\n```kotlin\nclass Test(var a: Int) {\n    // ...\n}\n\n// in case of any annotations or modifiers used on a constructor:\nclass Test private constructor(var a: Int) {\n    // ...\n}\n```\n\n#### <a name=\"r6.1.2\"></a> 6.1.2 Prefer data classes instead of classes without any functional logic\nSome people say that the data class is a code smell. However, if you need to use it (which makes your code more simple), you can utilize the Kotlin `data class`. The main purpose of this class is to hold data,\nbut also `data class` will automatically generate several useful methods:\n- equals()/hashCode() pair;\n- toString()\n- componentN() functions corresponding to the properties in their order of declaration;\n- copy() function\n\nTherefore, instead of using `normal` classes:\n\n```kotlin\nclass Test {\n    var a: Int = 0\n        get() = field\n        set(value: Int) { field = value}\n}\n\nclass Test {\n    var a: Int = 0\n    var b: Int = 0\n\n    constructor(a:Int, b: Int) {\n        this.a = a\n        this.b = b\n    }\n}\n\n// or\nclass Test(var a: Int = 0, var b: Int = 0)\n\n// or\nclass Test() {\n    var a: Int = 0\n    var b: Int = 0\n}\n```\n\n**prefer data classes:**\n```kotlin\ndata class Test1(var a: Int = 0, var b: Int = 0)\n```\n\n**Exception 1**: Note that data classes cannot be abstract, open, sealed, or inner; that is why these types of classes cannot be changed to a data class.\n\n**Exception 2**: No need to convert a class to a data class if this class extends some other class or implements an interface.\n\n#### <a name=\"r6.1.3\"></a> 6.1.3 Do not use the primary constructor if it is empty or useless\nThe primary constructor is a part of the class header; it is placed after the class name and type parameters (optional) but can be omitted if it is not used.\n\n**Invalid example**:\n```kotlin\n// simple case that does not need a primary constructor\nclass Test() {\n    var a: Int = 0\n    var b: Int = 0\n}\n\n// empty primary constructor is not needed here\n// it can be replaced with a primary contructor with one argument or removed\nclass Test() {\n    var a  = \"Property\"\n\n    init {\n        println(\"some init\")\n    }\n\n    constructor(a: String): this() {\n        this.a = a\n    }\n}\n```\n\n**Valid example**:\n```kotlin\n// the good example here is a data class; this example also shows that you should get rid of braces for the primary constructor\nclass Test {\n    var a: Int = 0\n    var b: Int = 0\n}\n```\n\n#### <a name=\"r6.1.4\"></a> 6.1.4 Do not use redundant init blocks in your class\nSeveral init blocks are redundant and generally should not be used in your class. The primary constructor cannot contain any code. That is why Kotlin has introduced `init` blocks.\nThese blocks store the code to be run during the class initialization.\nKotlin allows writing multiple initialization blocks executed in the same order as they appear in the class body.\nEven when you follow (rule 3.2)[#r3.2], this makes your code less readable as the programmer needs to keep in mind all init blocks and trace the execution of the code.\nTherefore, you should try to use a single `init` block to reduce the code's complexity. If you need to do some logging or make some calculations before the class property assignment, you can use powerful functional programming. This will reduce the possibility of the error if your `init` blocks' order is accidentally changed and\nmake the code logic more coupled. It is always enough to use one `init` block to implement your idea in Kotlin.\n\n**Invalid example**:\n```kotlin\nclass YourClass(var name: String) {\n    init {\n        println(\"First initializer block that prints ${name}\")\n    }\n\n    val property = \"Property: ${name.length}\".also(::println)\n\n    init {\n        println(\"Second initializer block that prints ${name.length}\")\n    }\n}\n```\n\n**Valid example**:\n```kotlin\nclass YourClass(var name: String) {\n    init {\n        println(\"First initializer block that prints ${name}\")\n    }\n\n    val property = \"Property: ${name.length}\".also { prop ->\n        println(prop)\n        println(\"Second initializer block that prints ${name.length}\")\n    }\n}\n```\n\nThe `init` block was not added to Kotlin to help you initialize your properties; it is needed for more complex tasks.\nTherefore if the `init` block contains only assignments of variables - move it directly to properties to be correctly initialized near the declaration.\nIn some cases, this rule can be in clash with [6.1.1](#r6.1.1), but that should not stop you.\n\n**Invalid example**:\n```kotlin\nclass A(baseUrl: String) {\n    private val customUrl: String\n    init {\n        customUrl = \"$baseUrl/myUrl\"\n    }\n}\n```\n\n**Valid example**:\n```kotlin\nclass A(baseUrl: String) {\n    private val customUrl = \"$baseUrl/myUrl\"\n}\n```\n\n#### <a name=\"r6.1.5\"></a> 6.1.5 Explicit supertype qualification\nThe explicit supertype qualification should not be used if there is no clash between called methods. This rule is applicable to both interfaces and classes.\n\n**Invalid example**:\n```kotlin\nopen class Rectangle {\n    open fun draw() { /* ... */ }\n}\n\nclass Square() : Rectangle() {\n    override fun draw() {\n        super<Rectangle>.draw() // no need in super<Rectangle> here\n    }\n}\n```\n\n#### <a name=\"r6.1.6\"></a> 6.1.6 Abstract class should have at least one abstract method\nAbstract classes are used to force a developer to implement some of its parts in their inheritors.\nWhen the abstract class has no abstract methods, it was set `abstract` incorrectly and can be converted to a regular class.\n\n**Invalid example**:\n```kotlin\nabstract class NotAbstract {\n    fun foo() {}\n\n    fun test() {}\n}\n```\n\n**Valid example**:\n```kotlin\nabstract class NotAbstract {\n    abstract fun foo()\n\n    fun test() {}\n}\n\n// OR\nclass NotAbstract {\n    fun foo() {}\n\n    fun test() {}\n}\n```\n\n\n#### <a name=\"r6.1.7\"></a> 6.1.7 When using the \"implicit backing property\" scheme, the name of real and back property should be the same\nKotlin has a mechanism of [backing properties](https://kotlinlang.org/docs/reference/properties.html#backing-properties).\nIn some cases, implicit backing is not enough and it should be done explicitly:\n```kotlin\nprivate var _table: Map<String, Int>? = null\nval table: Map<String, Int>\n    get() {\n        if (_table == null) {\n            _table = HashMap() // Type parameters are inferred\n        }\n        return _table ?: throw AssertionError(\"Set to null by another thread\")\n    }\n```\n\nIn this case, the name of the backing property (`_table`) should be the same as the name of the real property (`table`) but should have an underscore (`_`) prefix.\nIt is one of the exceptions from the [identifier names rule](#r1.2)\n\n#### <a name=\"r6.1.8\"></a> 6.1.8 Avoid using custom getters and setters\nKotlin has a perfect mechanism of [properties](https://kotlinlang.org/docs/reference/properties.html#properties-and-fields).\nKotlin compiler automatically generates `get` and `set` methods for properties and can override them.\n\n**Invalid example:**\n```kotlin\nclass A {\n    var size: Int = 0\n        set(value) {\n            println(\"Side effect\")\n            field = value\n        }\n        // user of this class does not expect calling A.size receive size * 2\n        get() = field * 2\n}\n```\n\nFrom the callee code, these methods look like access to this property: `A().isEmpty = true` for setter and `A().isEmpty` for getter.\n\nHowever, when `get` and `set` are overridden, it  isn't very clear for a developer who uses this particular class.\nThe developer expects to get the property value but receives some unknown value and some extra side-effect hidden by the custom getter/setter.\nUse extra functions instead to avoid confusion.\n\n\n\n**Valid example**:\n```kotlin\nclass A {\n    var size: Int = 0\n    fun initSize(value: Int) {\n        // some custom logic\n    }\n\n    // this will not confuse developer and he will get exactly what he expects\n    fun goodNameThatDescribesThisGetter() = this.size * 2\n}\n```\n\n**Exception:** `Private setters` are only exceptions that are not prohibited by this rule.\n\n#### <a name=\"r6.1.9\"></a> 6.1.9 Never use the name of a variable in the custom getter or setter (possible_bug)\nIf you ignored [recommendation 6.1.8](#r6.1.8), be careful with using the name of the property in your custom getter/setter\nas it can accidentally cause a recursive call and a `StackOverflow Error`. Use the `field` keyword instead.\n\n**Invalid example (very bad)**:\n```kotlin\nvar isEmpty: Boolean\n    set(value) {\n        println(\"Side effect\")\n        isEmpty = value\n    }\n    get() = isEmpty\n```\n\n#### <a name=\"r6.1.10\"></a> 6.1.10 No trivial getters and setters are allowed in the code\nIn Java, trivial getters - are the getters that are just returning the field value.\nTrivial setters - are merely setting the field with a value without any transformation.\nHowever, in Kotlin, trivial getters/setters are generated by default. There is no need to use it explicitly for all types of data structures in Kotlin.\n\n**Invalid example**:\n```kotlin\nclass A {\n    var a: Int = 0\n    get() = field\n    set(value: Int) { field = value }\n\n    //\n}\n```\n\n**Valid example**:\n```kotlin\nclass A {\n    var a: Int = 0\n    get() = field\n    set(value: Int) { field = value }\n\n    //\n}\n```\n\n#### <a name=\"r6.1.11\"></a> 6.1.11 Use 'apply' for grouping object initialization\nIn Java, before functional programming became popular, many classes from common libraries used the configuration paradigm.\nTo use these classes, you had to create an object with the constructor with 0-2 arguments and set the fields needed to run the object.\nIn Kotlin, to reduce the number of dummy code line and to group objects [`apply` extension](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/apply.html) was added:\n\n**Invalid example**:\n```kotlin\nclass HttpClient(var name: String) {\n    var url: String = \"\"\n    var port: String = \"\"\n    var timeout = 0\n\n    fun doRequest() {}\n}\n\nfun main() {\n    val httpClient = HttpClient(\"myConnection\")\n    httpClient.url = \"http://example.com\"\n    httpClient.port = \"8080\"\n    httpClient.timeout = 100\n\n    httpCLient.doRequest()\n}\n\n```\n\n**Valid example**:\n```kotlin\nclass HttpClient(var name: String) {\n    var url: String = \"\"\n    var port: String = \"\"\n    var timeout = 0\n\n    fun doRequest() {}\n}\n\nfun main() {\n    val httpClient = HttpClient(\"myConnection\")\n            .apply {\n                url = \"http://example.com\"\n                port = \"8080\"\n                timeout = 100\n            }\n    httpClient.doRequest()\n}\n```\n\n### <a name=\"r6.1.12\"></a> 6.1.12 Prefer Inline classes when a class has a single property\nIf a class has only one immutable property, then it can be converted to the inline class.\n\nSometimes it is necessary for business logic to create a wrapper around some type. However, it introduces runtime overhead due to additional heap allocations. Moreover, if the wrapped type is primitive, the performance hit is terrible, because primitive types are usually heavily optimized by the runtime, while their wrappers don't get any special treatment.\n\n**Invalid example**:\n```kotlin\nclass Password {\n    val value: String\n}\n```\n\n**Valid example**:\n```kotlin\ninline class Password(val value: String)\n```\n\n<!-- =============================================================================== -->\n### <a name=\"c6.2\"></a>6.2 Extension functions\nThis section describes the rules of using extension functions in your code.\n\n[Extension functions](https://kotlinlang.org/docs/reference/extensions.html) is a killer-feature in Kotlin.\nIt gives you a chance to extend classes that were already implemented in external libraries and helps you to make classes less heavy.\nExtension functions are resolved statically.\n\n#### <a name=\"r6.2.1\"></a> 6.2.1 Use extension functions for making logic of classes less coupled\nIt is recommended that for classes, the non-tightly coupled functions, which are rarely used in the class, should be implemented as extension functions where possible.\nThey should be implemented in the same class/file where they are used. This is a non-deterministic rule, so the code cannot be checked or fixed automatically by a static analyzer.\n\n#### <a name=\"r6.2.2\"></a> 6.2.2 No extension functions with the same name and signature if they extend base and inheritor classes (possible_bug)\nYou should avoid declaring extension functions with the same name and signature if their receivers are base and inheritor classes (possible_bug),\nas extension functions are resolved statically. There could be a situation when a developer implements two extension functions: one is for the base class and\nanother for the inheritor. This can lead to an issue when an incorrect method is used.\n\n**Invalid example**:\n```kotlin\nopen class A\nclass B: A()\n\n// two extension functions with the same signature\nfun A.foo() = \"A\"\nfun B.foo() = \"B\"\n\nfun printClassName(s: A) { println(s.foo()) }\n\n// this call will run foo() method from the base class A, but\n// programmer can expect to run foo() from the class inheritor B\nfun main() { printClassName(B()) }\n```\n\n#### <a name=\"r6.2.3\"></a> 6.2.3 Don't use extension functions for the class in the same file\nYou should not use extension functions for the class in the same file, where it is defined.\n\n**Invalid example**:\n```kotlin\nclass SomeClass {\n\n}\n\nfun SomeClass.deleteAllSpaces() {\n\n}\n```\n\n#### <a name=\"r6.2.4\"></a> 6.2.4 Use 'lastIndex' in case you need to get latest element of a collection\nYou should not use property length with operation - 1, you can change this to lastIndex\n\n**Invalid example**:\n```kotlin\nval A = \"name\"\nval B = A.length - 1\nval C = A[A.length - 1]\n```\n\n**Valid example**:\n```kotlin\nval A = \"name\"\nval B = A.lastIndex\nval C = A[A.lastIndex]\n```\n\n\n\n<!-- =============================================================================== -->\n### <a name=\"c6.3\"></a> 6.3 Interfaces\nAn `Interface` in Kotlin can contain declarations of abstract methods, as well as method implementations. What makes them different from abstract classes is that interfaces cannot store state.\nThey can have properties, but these need to be abstract or to provide accessor implementations.\n\nKotlin's interfaces can define attributes and functions.\nIn Kotlin and Java, the interface is the main presentation means of application programming interface (API) design and should take precedence over the use of (abstract) classes.\n\n<!-- =============================================================================== -->\n### <a name=\"c6.4\"></a> 6.4 Objects\nThis section describes the rules of using objects in code.\n#### <a name=\"r6.4.1\"></a> 6.4.1 Instead of using utility classes/objects, use extensions\nAvoid using utility classes/objects; use extensions instead. As described in [6.2 Extension functions](#c6.2), using extension functions is a powerful method.\nThis enables you to avoid unnecessary complexity and class/object wrapping and use top-level functions instead.\n\n**Invalid example**:\n```kotlin\nobject StringUtil {\n    fun stringInfo(myString: String): Int {\n        return myString.count{ \"something\".contains(it) }\n    }\n}\nStringUtil.stringInfo(\"myStr\")\n```\n\n**Valid example**:\n```kotlin\nfun String.stringInfo(): Int {\n    return this.count{ \"something\".contains(it) }\n}\n\n\"myStr\".stringInfo()\n```\n\n#### <a name=\"r6.4.2\"></a> 6.4.2 Objects should be used for Stateless Interfaces\nKotlin’s objects are extremely useful when you need to implement some interface from an external library that does not have any state.\nThere is no need to use classes for such structures.\n\n**Valid example**:\n```\ninterface I {\n    fun foo()\n}\n\nobject O: I {\n    override fun foo() {}\n}\n```\n### <a name=\"c6.5\"></a> 6.5 Kts Files\nThis section describes general rules for `.kts` files\n#### <a name=\"r6.5.1\"></a> 6.5.1 kts files should wrap logic into top-level scope\nIt is still recommended wrapping logic inside functions and avoid using top-level statements for function calls or wrapping blocks of code\nin top-level scope functions like `run`.\n\n**Valid example**:\n```\nrun {\n    // some code\n}\n\nfun foo() {\n\n}\n```\n"
  },
  {
    "path": "info/guide/guide-TOC.md",
    "content": "<img src=\"logo.svg\" width=\"64px\"/>\n\n# Kotlin Coding Style Guide (Diktat Code Style), v.1.0.0\n\nI [Preface](#c0)\n* [I.I Purpose of this document](#c0.1)\n* [I.II General principles](#c0.2)\n* [I.III Terminology](#c0.3)\n* [I.IV Exceptions](#c0.4)\n\n[1. Naming](#c1)\n\n* [1.1 Identifiers](#c1.1)\n* [1.2 Packages](#c1.2)\n* [1.3 Classes, enumerations, interfaces](#c1.3)\n* [1.4 Functions](#c1.4)\n* [1.5 Constants](#c1.5)\n* [1.6 Non-constant fields (variables)](#c1.6)\n    * [1.6.1 Non-constant field name](#r1.6.1)\n    * [1.6.2 Boolean variable names with negative meaning](#r1.6.2)\n\n[2. Comments](#c2)\n* [2.1 General form of Kdoc](#c2.1)\n    * [2.1.1 Using KDoc for the public, protected, or internal code elements](#r2.1.1)\n    * [2.1.2 Describing methods that have arguments, a return value, or can throw an exception in the KDoc block](#r2.1.2)\n    * [2.1.3 Only one space between the Kdoc tag and content. Tags are arranged in the order.](#r2.1.3)\n* [2.2 Adding comments on the file header](#c2.2)\n* [2.3 Comments on the function header](#c2.3)\n* [2.4 Code comments](#c2.4)\n    * [2.4.1 Adding a blank line between the body of the comment and Kdoc tag-blocks](#r2.4.1)\n    * [2.4.2 Do not comment on unused code blocks](#r2.4.2)\n    * [2.4.3 Code delivered to the client must not contain TODO/FIXME comments](#r2.4.3)\n\n[3. General formatting (typesetting)](#c3)\n* [3.1 File-related rules](#c3.1)\n    * [3.1.1 Avoid files that are too long](#r3.1.1)\n    * [3.1.2 Code blocks in the source file must be separated by one blank line](#r3.1.2)\n    * [3.1.3 Import statements order](#r3.1.3)\n    * [3.1.4 Order of declaration parts of class-like code structures](#r3.1.4)\n    * [3.1.5 Order of declaration of top-level code structures](#r3.1.5)\n* [3.2 Braces](#c3.2)\n    * [3.2.1 Using braces in conditional statements and loop blocks](#r3.2.1)\n    * [3.2.2 Opening braces are placed at the end of the line in *non-empty* blocks and block structures](#r3.2.2)\n* [3.3 Indentation](#c3.3)\n* [3.4 Empty blocks](#c3.4)\n* [3.5 Line length](#c3.5)\n* [3.6 Line breaks (newlines)](#c3.6)\n    * [3.6.1 Each line can have a maximum of one statement](#r3.6.1)\n    * [3.6.2 Rules for line-breaking](#r3.6.2)\n* [3.7 Using blank lines](#c3.7)\n* [3.8 Horizontal space](#c3.8)\n    * [3.8.1 Using whitespace for code separation](#r3.8.1)\n    * [3.8.2 No spaces for horizontal alignment](#r3.8.2)\n* [3.9 Enumerations](#c3.9)\n* [3.10 Variable declaration](#c3.10)\n    * [3.10.1 Declare one variable per line](#r3.10.1)\n    * [3.10.2 Variables should be declared near the line where they are first used](#r3.10.2)\n* [3.11 'When' expression](#c3.11)\n* [3.12 Annotations](#c3.12)\n* [3.13 Block comments](#c3.13)\n* [3.14 Modifiers and constant values](#c3.14)\n    * [3.14.1 Declaration with multiple modifiers](#r3.14.1)\n    * [3.14.2 Separating long numerical values with an underscore](#r3.14.2)\n * [3.15 Strings](#c3.15)\n     * [3.15.1 Concatenation of Strings](#r3.15.1)\n     * [3.15.2 String template format](#r3.15.2)\n * [3.16 Conditional statements](#c3.16)\n     * [3.16.1 Collapsing redundant nested if-statements](#r3.16.1)\n     * [3.16.2 Too complex conditions](#r3.16.2)\n\n[4. Variables and types](#c4)\n* [4.1 Variables](#c4.1)\n    * [4.1.1 Do not use Float and Double types when accurate calculations are needed](#r4.1.1)\n    * [4.1.2 Comparing numeric float type values](#r4.1.2)\n    * [4.1.3 Using 'val' instead of 'var' for variable declaration [SAY_NO_TO_VAR]](#r4.1.3)\n* [4.2 Types](#c4.2)\n    * [4.2.1 Using Contracts and smart cast as much as possible](#r4.2.1)\n    * [4.2.2 Trying to use type alias to represent types making code more readable](#r4.2.2)\n* [4.3 Null safety and variable declarations](#c4.3)\n    * [4.3.1 Avoid declaring variables with nullable types, especially from Kotlin stdlib](#r4.3.1)\n    * [4.3.2 Variables of generic types should have an explicit type declaration](#r4.3.2)\n    * [4.3.3 Null-safety](#r4.3.3)\n\n[5. Functions](#c5)\n* [5.1 Function design](#c5.1)\n    * [5.1.1 Avoid functions that are too long ](#r5.1.1)\n    * [5.1.2 Avoid deep nesting of function code blocks, limiting to four levels](#r5.1.2)\n    * [5.1.3 Avoid using nested functions](#r5.1.3)\n    * [5.1.4 Negated function calls](#r5.1.4)\n* [5.2 Function arguments](#c5.2)\n    * [5.2.1 The lambda parameter of the function should be placed at the end of the argument list](#r5.2.1)\n    * [5.2.2 Number of function parameters should be limited to five](#r5.2.2)\n    * [5.2.3 Use default values for function arguments instead of overloading them](#r5.2.3)\n    * [5.2.4 Synchronizing code inside asynchronous code](#r5.2.4)\n    * [5.2.5 Long lambdas must have explicit parameters](#r5.2.5)\n    * [5.2.6 Avoid using unnecessary, custom label](#r5.2.6)\n\n[6. Classes, interfaces, and extension functions](#c6)\n* [6.1 Classes](#c6.1)\n    * [6.1.1 Denoting a class with a single constructor](#r6.1.1)\n    * [6.1.2 Prefer data classes instead of classes without any functional logic](#r6.1.2)\n    * [6.1.3 Do not use the primary constructor if it is empty or useless](#r6.1.3)\n    * [6.1.4 Do not use redundant init blocks in your class](#r6.1.4)\n    * [6.1.5 Explicit supertype qualification](#r6.1.5)\n    * [6.1.6 Abstract class must have at least one abstract method](#r6.1.6)\n    * [6.1.7 When using the \"implicit backing property\" scheme, the name of real and back property should be the same](#r6.1.7)\n    * [6.1.8 Avoid using custom getters and setters](#r6.1.8)\n    * [6.1.9 Never use the name of a variable in the custom getter or setter (possible_bug)](#r6.1.9)\n    * [6.1.10 No trivial getters and setters are allowed in the code](#r6.1.10)\n    * [6.1.11 Use 'apply' for grouping object initialization](#r6.1.11)\n    * [6.1.12 Prefer Inline classes when the class has a single property](#r6.1.12)\n* [6.2 Extension functions](#c6.2)\n    * [6.2.1 Use extension functions for making logic of classes less coupled](#r6.2.1)\n    * [6.2.2 No extension functions with the same name and signature if they extend base and inheritor classes (possible_bug)](#r6.2.2)\n    * [6.2.3 Don't use extension functions for the class in the same file](#r6.2.3)\n* [6.3 Interfaces](#c6.3)\n* [6.4 Objects](#c6.4)\n    * [6.4.1 Instead of using utility classes/objects, use extensions](#r6.4.1)\n    * [6.4.2 Objects must be used for Stateless Interfaces](#r6.4.2)\n* [6.5 Kts Files](#c6.5)\n    * [6.5.1 kts files should wrap logic into top-level scope](#r6.5.1)\n"
  },
  {
    "path": "info/guide/guide-chapter-0.md",
    "content": "## <a name=\"c0\"></a> Preface\n <!-- =============================================================================== -->\n### <a name=\"c0.1\"></a> Purpose of this document\n\nThe purpose of this document is to provide a specification that software developers could reference to enhance their ability to write consistent, easy-to-read, and high-quality code.\nSuch a specification will ultimately improve software development efficiency and product competitiveness.\nFor the code to be considered high-quality, it must entail the following characteristics:\n1.\tSimplicity\n2.\tMaintainability\n3.\tReliability\n4.\tTestability\n5.\tEfficiency\n6.\tPortability\n7.\tReusability\n\n\n<!-- =============================================================================== -->\n### <a name=\"c0.2\"></a> General principles\n\nLike other modern programming languages, Kotlin is an advanced programming language that complies with the following general principles:\n1.\tClarity — a necessary feature of programs that are easy to maintain and refactor.\n2.\tSimplicity — a code is easy to understand and implement.\n3.\tConsistency — enables a code to be easily modified, reviewed, and understood by the team members. Unification is particularly important when the same team works on the same project, utilizing similar styles enabling a code to be easily modified, reviewed, and understood by the team members.\n\nAlso, we need to consider the following factors when programming on Kotlin:\n\n1. Writing a clean and simple Kotlin code\n\n    Kotlin combines two of the main programming paradigms: functional and object-oriented.\n    Both of these paradigms are trusted and well-known software engineering practices.\n    As a young programming language, Kotlin is built on top of well-established languages such as Java, C++, C#, and Scala.\n    This enables Kotlin to introduce many features that help a developer write cleaner, more readable code while also reducing the number of complex code structures. For example, type and null safety, extension functions, infix syntax, immutability, val/var differentiation, expression-oriented features, \"when\" statements, much easier work with collections, type auto conversion, and other syntactic sugar.\n\n2. Following Kotlin idioms\n\n    The author of Kotlin, Andrey Breslav, mentioned that Kotlin is both pragmatic and practical, but not academic.\n    Its pragmatic features enable ideas to be transformed into real working software easily. Kotlin is closer to natural languages than its predecessors, and it implements the following design principles: readability, reusability, interoperability, security, and tool-friendliness (https://blog.jetbrains.com/kotlin/2018/10/kotlinconf-2018-announcements/).\n\n3. Using Kotlin efficiently\n\n    Some Kotlin features can help you write high-performance code. Such features include: rich coroutine library, sequences, inline functions/classes, arrays of basic types, tailRec, and CallsInPlace of contract.\n\n<!-- =============================================================================== -->\n### <a name=\"c0.3\"></a> Terminology\n\n**Rules** — conventions that should be followed when programming.\n\n**Recommendations** — conventions that should be considered when programming.\n\n**Explanation** — necessary explanations of rules and recommendations.\n\n**Valid Example** — recommended examples of rules and recommendations.\n\n**Invalid Example** — not recommended examples of rules and recommendations.\n\nUnless otherwise stated, this specification applies to versions 1.3 and later of Kotlin.\n\n<!-- =============================================================================== -->\n### <a name=\"c0.4\"></a> Exceptions\n\nEven though exceptions may exist, it is essential to understand why rules and recommendations are needed.\nDepending on a project situation or personal habits, you can break some of the rules. However, remember that one exception may lead to many and eventually can destroy code consistency. As such, there should be very few exceptions.\nWhen modifying open-source code or third-party code, you can choose to use the code style from this open-source project (instead of using the existing specifications) to maintain consistency.\nThe software that is directly based on the Android native operating system interface, such as the Android Framework, remains consistent with the Android style.\n"
  },
  {
    "path": "info/guide/guide-chapter-1.md",
    "content": "# <a name=\"c1\"></a> 1. Naming\nIt is not always easy to meaningfully and appropriately name variables, functions, classes, and so on. Using meaningful names in programming helps to clearly express the main ideas and functionality of your code and avoid its misinterpretation, unnecessary coding and decoding, \"magic\" numbers, and inappropriate abbreviations.\n\nNote: Source code files (incl. comments) must be UTF-8 encoded, no exceptions. The ASCII horizontal space (`0x20`, `U+0020`) is the only permitted whitespace character. Tab character (`0x09`, `U+0009`) should never be used for indentation.\n\n<!-- =============================================================================== -->\n### <a name=\"c1.1\"></a> 1.1 Identifiers\nThis section describes the general rules for naming identifiers.\n#### <a name=\"r1.1.1\"></a> 1.1.1 Identifiers naming conventions\n\nFor identifiers, use the following naming conventions:\n1.\tAll identifiers should use only ASCII letters or digits, and the names should match regular expressions `\\w{2,64}`.\nExplanation: Each valid identifier name should match the regular expression `\\w{2,64}`, which means that the name length is 2 to 64 characters, and the length of the variable name should be proportional to its life range and describe its functionality and responsibility.\nLength of names depends on the project. Nevertheless, name lengths of less than 31 characters are generally recommended. Otherwise, a class declaration with generics or inheritance from a superclass can cause line breaking.\nNo special prefix or suffix should be used in names. The examples of inappropriate names are: name_, mName, s_name, and kName.\n\n2.\tChoose file names that would describe the content. Use camel case (PascalCase) and `.kt` extension.\n\n3.\tTypical examples of naming:\n\n| Meaning | Correct |Incorrect|\n| ---- | ---- | ---- |\n| \"XML Http Request\" | XmlHttpRequest | XMLHTTPRequest |\n| \"new customer ID\" | newCustomerId | newCustomerID |\n| \"inner stopwatch\" | innerStopwatch | innerStopWatch |\n| \"supports IPv6 on iOS\" | supportsIpv6OnIos | supportsIPv6OnIOS |\n| \"YouTube importer\" | YouTubeImporter | YoutubeImporter |\n\n4.\tThe usage of (``) and free naming for functions and identifiers are prohibited. For example, the following code is not recommended:\n\n```kotlin\nval `my dummy name-with-minus` = \"value\" \n```\n\nThe only exceptions are function names in `Unit tests.`\n\n5.\tBackticks (``) must not be used for identifiers, except for the names of test methods (marked with @Test annotation):\n```kotlin\n @Test fun `my test`() { /*...*/ }\n``` \n6.  The following table contains some characters that may cause confusion. Be careful when using them as identifiers. To avoid issues, use other names instead.\n\n| Expected      | Confusing name           | Suggested name   |\n| ------------- | ------------------------ | ---------------- |\n| 0 (zero)      | O, D                     | obj, dgt         |\n| 1 (one)       | I, l                     | it, ln, line     |\n| 2 (two)       | Z                        | n1, n2           |\n| 5 (five)      | S                        | xs, str          |\n| 6 (six)       | e                        | ex, elm          |\n| 8 (eight)     | B                        | bt, nxt          |\n| n,h           | h,n                      | nr, head, height |\n| rn, m         | m,rn                     | mbr, item        |\n\n**Exceptions:**\n- The `i`,`j`,`k` variables used in loops are part of the industry standard. A single character can be used for such variables.\n- The `e` variable can be used to catch exceptions in the catch block: `catch (e: Exception) {}`\n- The Java community normally does not recommend the use of prefixes. However, when developing the Android code, you can use the \"s\" and \"m\" prefixes for static and non-public non-static fields, respectively.\nNote that prefixing can also negatively affect the style and the auto-generation of getters and setters.\n\n| Type | Naming style |\n| ---- | ---- |\n| Interfaces, classes, annotations, enumerated types, and object type names | Camel case, starting with a capital letter. Test classes have a Test suffix. The filename is 'TopClassName'.kt.  |\n| Class fields, local variables, methods, and method parameters | Camel case, starting with a low case letter. Test methods can be underlined with '_'; the only exception is [backing properties](#r6.1.7).\n| Static constants and enumerated values | Only the uppercase underlined with '_' |\n| Generic type variable | Single capital letter, which can be followed by a number, for example: `E, T, U, X, T2` |\n| Exceptions | Same as class names, but with a suffix Exception, for example: `AccessException` and `NullPointerException`|\n\n<!-- =============================================================================== -->\n### <a name=\"c1.2\"></a> 1.2 Packages\n\n#### <a name=\"r1.2.1\"></a> Rule 1.2.1 Package names dots\nPackage names are in the lower case and separated by dots. The code developed within your company should start with `your.company.domain.` Numbers are permitted in package names.\nEach file should have a `package` directive.\nPackage names are all written in lowercase, and consecutive words are concatenated (no underscores). Package names should contain both the product or module names and the department (or team) name to prevent conflicts with other teams.  Numbers are not permitted. For example: `org.apache.commons.lang3`, `xxx.yyy.v2`.\n\n**Exceptions:** \n\n- In certain cases, such as open-source projects or commercial cooperation, package names should not start with `your.company.domain.`\n- If the package name starts with a number or other character that cannot be used at the beginning of the Java/Kotlin package name, then underscores are allowed. For example: `com.example._123name`.\n- Underscores are sometimes permitted if the package name contains reserved Java/Kotlin keywords, such as `org.example.hyphenated_name`, `int_.example`.\n\n**Valid example**: \n```kotlin\npackage your.company.domain.mobilecontrol.views\n```\n\n<!-- =============================================================================== -->\n### <a name=\"c1.3\"></a> 1.3 Classes, enumerations, typealias, interfaces\nThis section describes the general rules for naming classes, enumerations, and interfaces.\n### <a name=\"r1.3.1\"></a> 1.3.1 Classes, enumerations, typealias, interface names use Camel case\nClasses, enumerations, and interface names use `UpperCamelCase` nomenclature. Follow the naming rules described below:\n1.\tA class name is usually a noun (or a noun phrase) denoted using the camel case nomenclature, such as the UpperCamelCase. For example: `Character` or `ImmutableList`.\nAn interface name can also be a noun or noun phrase (such as `List`) or an adjective or adjective phrase (such as `Readable`).\nNote that verbs are not used to name classes. However, nouns (such as `Customer`, `WikiPage`, and `Account`) can be used. Try to avoid using vague words such as `Manager` and `Process`.\n\n2.\tTest classes start with the name of the class they are testing and end with 'Test'. For example, `HashTest` or `HashIntegrationTest`.\n\n**Invalid example**: \n```kotlin\nclass marcoPolo {} \nclass XMLService {} \ninterface TAPromotion {}\nclass info {}\n```\n\n**Valid example**: \n```kotlin\nclass MarcoPolo {}\nclass XmlService {}\ninterface TaPromotion {}\nclass Order {}\n```\n\n<!-- =============================================================================== -->\n### <a name=\"c1.4\"></a> 1.4 Functions\nThis section describes the general rules for naming functions.\n### <a name=\"r1.4.1\"></a> 1.4.1 Function names should be in camel case\nFunction names should use `lowerCamelCase` nomenclature. Follow the naming rules described below:\n1.\tFunction names are usually verbs or verb phrases denoted with the camel case nomenclature (`lowerCamelCase`).\nFor example: `sendMessage`, `stopProcess`, or `calculateValue`.\nTo name functions, use the following formatting rules:\n\na) To get, modify, or calculate a certain value: get + non-boolean field(). Note that the Kotlin compiler automatically generates getters for some classes, applying the special syntax preferred for the 'get' fields: kotlin private val field: String get() { }. kotlin private val field: String get() { }.\n```kotlin\nprivate val field: String\nget() {\n}\n``` \nNote: The calling property access syntax is preferred to call getter directly. In this case, the Kotlin compiler automatically calls the corresponding getter.\n\nb) `is` + boolean variable name()\n\nc) `set` + field/attribute name(). However, note that the syntax and code generation for Kotlin are completely the same as those described for the getters in point a.\n\nd) `has` + Noun / adjective ()\n\ne) verb()\nNote: Verb are primarily used for the action objects, such as `document.print ()`\n\nf) verb + noun() \n\ng) The Callback function allows the names that use the preposition + verb format, such as `onCreate()`, `onDestroy()`, `toString()`.\n\n**Invalid example**: \n\n```kotlin\nfun type(): String\nfun Finished(): Boolean\nfun visible(boolean)\nfun DRAW()\nfun KeyListener(Listener)\n```\n\n**Valid example**: \n\n```kotlin\nfun getType(): String\nfun isFinished(): Boolean\nfun setVisible(boolean)\nfun draw()\nfun addKeyListener(Listener)\n```\n\n2.\tAn underscore (`_`) can be included in the JUnit test function name and should be used as a separator. Each logical part is denoted in `lowerCamelCase`, for example, a typical pattern of using underscore: `pop_emptyStack`.\n<!-- =============================================================================== -->\n### <a name=\"c1.5\"></a> 1.5 Constants\nThis section describes the general rules for naming constraints.\n### <a name=\"r1.5.1\"></a> 1.5.1 Using UPPER case and underscore characters in a constraint name\nConstant names should be in the UPPER case, words separated by an underscore. The general constant naming conventions are listed below:\n1. Constants are attributes created with the `const` keyword or top-level/`val` local variables of an object that holds immutable data. In most cases, constants can be identified as a `const val` property from the `object`/`companion object`/file top level. These variables contain fixed constant values that typically should never be changed by programmers. This includes basic types, strings, immutable types, and immutable collections of immutable types. The value is not constant for the object, which state can be changed.\n2. Constant names should contain only uppercase letters separated by underscores. They should have a val or const val modifier to make them final explicitly. In most cases, if you need to specify a constant value, then you need to create it with the \"const val\" modifier. Note that not all `val` variables are constants.\n3. Objects with immutable content, such as `Logger` and `Lock`, they can be in the uppercase as constants or have the Camel case as regular variables.\n4. Use meaningful constants instead of `magic numbers`. SQL or logging strings should not be treated as magic numbers, nor should they be defined as string constants.\nMagic constants, such as `NUM_FIVE = 5` or `NUM_5 = 5`, should not be treated as constants. This is because mistakes will easily be made if they are changed to `NUM_5 = 50` or 55.\nThese constants typically represent business logic values, such as measures, capacity, scope, location, tax rate, promotional discounts, and power base multiples in algorithms.\nYou can avoid using magic numbers with the following method:\n- Using library functions and APIs. For example, instead of checking that `size == 0`, use `isEmpty()` function. To work with `time`, use built-ins from `java.time API`.\n- Enumerations can be used to name patterns. Refer to [Recommended usage scenario for enumeration in 3.9](#c3.9).\n\n**Invalid example**: \n\n```kotlin\nvar int MAXUSERNUM = 200;\nval String sL = \"Launcher\";\n```\n\n**Valid example**:\n\n```kotlin\nconst val int MAX_USER_NUM = 200;\nconst val String APPLICATION_NAME = \"Launcher\";\n```\n\n<!-- =============================================================================== -->\n### <a name=\"c1.6\"></a> 1.6 Non-constant fields (variables)\nThis section describes the general rules for naming variables.\n### <a name=\"r1.6.1\"></a> 1.6.1 Non-constant field name\nNon-constant field names should use the Camel case and start with a lowercase letter.\nA local variable cannot be treated as constant, even if it is final and immutable. Therefore, it should not use the preceding rules. Names of collection type variables (sets, lists, etc.) should contain plural nouns.\nFor example: `var namesList: List<String>`\n\nNames of non-constant variables should use `lowerCamelCase`. The name of the final immutable field used to store the singleton object can use the same camel case notation.\n\n**Invalid example**: \n```kotlin\ncustomername: String\nuser: List<String> = listof()\n```\n\n**Valid example**: \n```kotlin\nvar customerName: String\nval users: List<String> = listOf();\nval mutableCollection: MutableSet<String> = HashSet()\n```\n\n### <a name=\"r1.6.2\"></a> 1.6.2 Boolean variable names with negative meaning\n\nAvoid using Boolean variable names with a negative meaning. When using a logical operator and name with a negative meaning, the code may be difficult to understand, which is referred to as the \"double negative\".\nFor instance, it is not easy to understand the meaning of !isNotError.\nThe JavaBeans specification automatically generates isXxx() getters for attributes of Boolean classes.\nHowever, not all methods returning the Boolean type have this notation.\nFor Boolean local variables or methods, it is highly recommended that you add non-meaningful prefixes, including is (commonly used by JavaBeans), has, can, should, and must. Modern integrated development environments (IDEs), such as Intellij, can doing this when you generate getters in Java. For Kotlin, this process is even more straightforward as everything is on the byte-code level under the hood.\n\n**Invalid example**: \n```kotlin\nval isNoError: Boolean\nval isNotFound: Boolean\nfun empty()\nfun next();\n```\n\n**Valid example**:\n```kotlin\nval isError: Boolean\nval isFound: Boolean\nval hasLicense: Boolean\nval canEvaluate: Boolean\nval shouldAbort: Boolean\nfun isEmpty()\nfun hasNext()\n```\n"
  },
  {
    "path": "info/guide/guide-chapter-2.md",
    "content": "# <a name=\"c2\"></a> 2. Comments\n\nThe best practice is to begin your code with a summary, which can be one sentence.\nTry to balance between writing no comments at all and obvious commentary statements for each line of code.\nComments should be accurately and clearly expressed, without repeating the name of the class, interface, or method.\nComments are not a solution to the wrong code. Instead, you should fix the code as soon as you notice an issue or plan to fix it (by entering a TODO comment, including a Jira number).\nComments should accurately reflect the code's design ideas and logic and further describe its business logic.\nAs a result, other programmers will be able to save time when trying to understand the code.\nImagine that you are writing the comments to help yourself to understand the original ideas behind the code in the future. \n\n### <a name=\"c2.1\"></a> 2.1 General form of Kdoc\n\nKDoc is a combination of JavaDoc's block tags syntax (extended to support specific constructions of Kotlin) and Markdown's inline markup.\nThe basic format of KDoc is shown in the following example:\n\n```kotlin\n /**\n * There are multiple lines of KDoc text,\n * Other ...\n */\nfun method(arg: String) {\n    // ...\n}\n```\n\nIt is also shown in the following single-line form:\n\n```kotlin\n /** Short form of KDoc. */\n```\nUse a single-line form when you store the entire KDoc block in one line (and there is no KDoc mark @XXX). For detailed instructions on how to use KDoc, refer to [Official Document](https://docs.oracle.com/en/Kotlin/Kotlinse/11/tools/KDoc.html).\n\n#### <a name=\"r2.1.1\"></a> 2.1.1 Using KDoc for the public, protected, or internal code elements\n\nAt a minimum, KDoc should be used for every public, protected, or internal decorated class, interface, enumeration, method, and member field (property).\nInstead of using comments or KDocs before properties in the primary constructor of a class - use `@property` tag in a KDoc of a class.\nAll properties of the primary constructor should also be documented in a KDoc with a `@property` tag.\n\n\n**Incorrect example:**\n```kotlin\n/**\n * Class description\n */\nclass Example(\n /**\n  * property description\n  */\n  val foo: Foo,\n  // another property description\n  val bar: Bar\n)\n```\n\n**Correct example:**\n```kotlin\n/**\n * Class description\n * @property foo property description\n * @property bar another property description\n */\nclass Example(\n  val foo: Foo,\n  val bar: Bar\n)\n```\n\n**Exceptions:**\n\n* For setters/getters of properties, obvious comments (like `this getter returns field`) are optional. Note that Kotlin generates simple `get/set` methods under the hood.\n   \n* It is optional to add comments for simple one-line methods, such as shown in the example below:\n```kotlin\nval isEmpty: Boolean\n    get() = this.size == 0\n```\n\nor\n\n```kotlin\nfun isEmptyList(list: List<String>) = list.size == 0\n```\n\n**Note:** You can skip KDocs for a method's override if it is almost the same as the superclass method.\n- \n- Don't use Kdoc comments inside code blocks as block comments\n\n**Incorrect Example:**\n\n```kotlin\nclass Example {\n  fun doGood() {\n    /**\n     * wrong place for kdoc\n     */\n    1 + 2\n  }\n}\n```\n\n**Correct Example:**\n\n```kotlin\nclass Example {\n  fun doGood() {\n    /*\n     * right place for block comment\n    */\n    1 + 2\n  }\n}\n```\n\n#### <a name=\"r2.1.2\"></a> 2.1.2 Describing methods that have arguments, a return value, or can throw an exception in the KDoc block\n\nWhen the method has such details as arguments, return value, or can throw exceptions, it must be described in the KDoc block (with @param, @return, @throws, etc.).\n\n**Valid examples:**\n\n ```kotlin\n/** \n * This is the short overview comment for the example interface.\n *     / * Add a blank line between the comment text and each KDoc tag underneath * /\n * @since 1.6\n */\n protected abstract class Sample {\n    /**\n     * This is a long comment with whitespace that should be split in \n     * comments on multiple lines if the line comment formatting is enabled.\n     *     / * Add a blank line between the comment text and each KDoc tag underneath * /\n     * @param fox A quick brown fox jumps over the lazy dog\n     * @return battle between fox and dog \n     */\n    protected abstract fun foo(Fox fox)\n     /**\n      * These possibilities include: Formatting of header comments\n      *     / * Add a blank line between the comment text and each KDoc tag underneath * /\n      * @return battle between fox and dog\n      * @throws ProblemException if lazy dog wins\n      */\n    protected fun bar() throws ProblemException {\n        // Some comments / * No need to add a blank line here * /   \n        var aVar = ...\n\n        // Some comments  / * Add a blank line before the comment * /   \n        fun doSome()\n    }\n }\n ```\n\n#### <a name=\"r2.1.3\"></a>2.1.3 Only one space between the Kdoc tag and content. Tags are arranged in the order.\n\nThere should be only one space between the Kdoc tag and content. Tags are arranged in the following order: @param, @return, and @throws.\n\nTherefore, Kdoc should contain the following:\n- Functional and technical description, explaining the principles, intentions, contracts, API, etc.\n- The function description and @tags (`implSpec`, `apiNote`, and `implNote`) require an empty line after them.\n- `@implSpec`: A specification related to API implementation, and it should let the implementer decide whether to override it.\n- `@apiNote`: Explain the API precautions, including whether to allow null and whether the method is thread-safe, as well as the algorithm complexity, input, and output range, exceptions, etc.\n- `@implNote`: A note related to API implementation, which implementers should keep in mind.\n- One empty line, followed by regular `@param`, `@return`, `@throws`, and other comments.\n- The conventional standard \"block labels\" are arranged in the following order: `@param`, `@return`, `@throws`.\nKdoc should not contain:\n- Empty descriptions in tag blocks. It is better not to write Kdoc than waste code line space.\n- There should be no empty lines between the method/class declaration and the end of Kdoc (`*/` symbols).\n- `@author` tag. It doesn't matter who originally created a class when you can use `git blame` or VCS of your choice to look through the changes history.\nImportant notes:\n- KDoc does not support the `@deprecated` tag. Instead, use the `@Deprecated` annotation.\n- The `@since` tag should be used for versions only. Do not use dates in `@since` tag, it's confusing and less accurate.\n\nIf a tag block cannot be described in one line, indent the content of the new line by *four spaces* from the `@` position to achieve alignment (`@` counts as one + three spaces).\n \n**Exception:**\n \nWhen the descriptive text in a tag block is too long to wrap, you can indent the alignment with the descriptive text in the last line. The descriptive text of multiple tags does not need to be aligned.\nSee [3.8 Horizontal space](#c3.8).\n\nIn Kotlin, compared to Java, you can put several classes inside one file, so each class should have a Kdoc formatted comment (as stated in rule 2.1).\nThis comment should contain @since tag. The right style is to write the application version when its functionality is released. It should be entered after the `@since` tag.\n\n**Examples:**\n\n```kotlin\n/**\n * Description of functionality\n *\n * @since 1.6\n */\n```\n\nOther KDoc tags (such as @param type parameters and @see.) can be added as follows:\n```kotlin\n/**\n * Description of functionality\n *\n * @apiNote: Important information about API\n *\n * @since 1.6\n */\n```\n\n### <a name=\"c2.2\"></a> 2.2 Adding comments on the file header\n\nThis section describes the general rules of adding comments on the file header.\n\n### <a name=\"r2.2.1\"></a> 2.2.1 Formatting of comments in the file header\n\nComments on the file header should be placed before the package name and imports. If you need to add more content to the comment, subsequently add it in the same format.\n\nComments on the file header must include copyright information, without the creation date and author's name (use VCS for history management).\nAlso, describe the content inside files that contain multiple or no classes.\n\nThe following examples for Huawei describe the format of the *copyright license*: \\\nChinese version: `版权所有 (c) 华为技术有限公司 2012-2020` \\\nEnglish version: `Copyright (c) Huawei Technologies Co., Ltd. 2012-2020. All rights reserved.`\n`2012` and `2020` are the years the file was first created and the current year, respectively.\n\nDo not place **release notes** in header, use VCS to keep track of changes in file. Notable changes can be marked in individual KDocs using `@since` tag with version.\n\nInvalid example:\n```kotlin\n/**\n * Release notes:\n * 2019-10-11: added class Foo\n */\n\nclass Foo\n```\n\nValid example:\n```kotlin\n/**\n * @since 2.4.0\n */\nclass Foo\n```\n\n- The **copyright statement** can use your company's subsidiaries, as shown in the below examples: \\\nChinese version: `版权所有 (c) 海思半导体 2012-2020` \\\nEnglish version: `Copyright (c) Hisilicon Technologies Co., Ltd. 2012-2020. All rights reserved.` \n\n- The copyright information should not be written in KDoc style or use single-line comments. It must start from the beginning of the file.\nThe following example is a copyright statement for Huawei, without other functional comments:\n\n```kotlin\n/*\n * Copyright (c) Huawei Technologies Co., Ltd. 2012-2020. All rights reserved.\n */\n```\n\nThe following factors should be considered when writing the file header or comments for top-level classes:\n- File header comments must start from the top of the file. If it is a top-level file comment, there should be a blank line after the last Kdoc `*/` symbol. If it is a comment for a top-level class, the class declaration should start immediately without using a newline.\n- Maintain a unified format. The specific format can be formulated by the project (for example, if you use an existing opensource project), and you need to follow it.\n- A top-level file-Kdoc must include a copyright and functional description, especially if there is more than one top-level class.\n- Do not include empty comment blocks. If there is no content after the option `@apiNote`, the entire tag block should be deleted.\n- The industry practice is not to include historical information in the comments. The corresponding history can be found in VCS (git, svn, etc.). Therefore, it is not recommended to include historical data in the comments of the Kotlin source code.\n\n### <a name=\"c2.3\"></a> 2.3 Comments on the function header\n\nComments on the function header are placed above function declarations or definitions. A newline should not exist between a function declaration and its Kdoc. Use the preceding <<c2.1,KDoc>> style rules.\n\nAs stated in Chapter 1, the function name should reflect its functionality as much as possible. Therefore, in the Kdoc, try to describe the functionality that is not mentioned in the function name.\nAvoid unnecessary comments on dummy coding.\n\nThe function header comment's content is optional, but not limited to function description, return value, performance constraints, usage, memory conventions, algorithm implementation, reentrant requirements, etc.\n\n### <a name=\"c2.4\"></a> 2.4 Code comments\n\nThis section describes the general rules of adding code comments.\n\n#### <a name=\"r2.4.1\"></a> 2.4.1 Add a blank line between the body of the comment and Kdoc tag-blocks.\n\nIt is a good practice to add a blank line between the body of the comment and Kdoc tag-blocks. Also, consider the following rules:\n- There must be one space between the comment character and the content of the comment.\n- There must be a newline between a Kdoc and the presiding code.\n- An empty line should not exist between a Kdoc and the code it is describing. You do not need to add a blank line before the first comment in a particular namespace (code block) (for example, between the function declaration and first comment in a function body).\n\n**Valid Examples:**\n\n```kotlin\n/** \n * This is the short overview comment for the example interface.\n * \n * @since 1.6\n */\n public interface Example {\n    // Some comments  /* Since it is the first member definition in this code block, there is no need to add a blank line here */\n    val aField: String = ...\n                     /* Add a blank line above the comment */\n    // Some comments\n    val bField: String = ...\n                      /* Add a blank line above the comment */\n    /**\n     * This is a long comment with whitespace that should be split in \n     * multiple line comments in case the line comment formatting is enabled.\n     *                /* blank line between description and Kdoc tag */\n     * @param fox A quick brown fox jumps over the lazy dog\n     * @return the rounds of battle of fox and dog \n     */\n    fun foo(Fox fox)\n                      /* Add a blank line above the comment */\n     /**\n      * These possibilities include: Formatting of header comments\n      * \n      * @return the rounds of battle of fox and dog\n      * @throws ProblemException if lazy dog wins\n      */\n    fun bar() throws ProblemException {\n        // Some comments  /* Since it is the first member definition in this range, there is no need to add a blank line here */\n        var aVar = ...\n\n        // Some comments  /* Add a blank line above the comment */            \n        fun doSome()\n    }\n }\n```\n\n- Leave one single space between the comment on the right side of the code and the code. \nIf you use conditional comments in the `if-else-if` scenario, put the comments inside the `else-if` branch or in the conditional block, but not before the `else-if`. This makes the code more understandable.\nWhen the if-block is used with curly braces, the comment should be placed on the next line after opening the curly braces.\nCompared to Java, the `if` statement in Kotlin statements returns a value. For this reason, a comment block can describe a whole `if-statement`.\n\n**Valid examples:**\n\n```kotlin\n\nval foo = 100  // right-side comment\nval bar = 200  /* right-side comment */\n\n// general comment for the value and whole if-else condition\nval someVal = if (nr % 15 == 0) {\n    // when nr is a multiple of both 3 and 5\n    println(\"fizzbuzz\")\n} else if (nr % 3 == 0) {\n    // when nr is a multiple of 3, but not 5\n    // We print \"fizz\", only.\n    println(\"fizz\")\n} else if (nr % 5 == 0) {\n    // when nr is a multiple of 5, but not 3\n    // we print \"buzz\" only.\n    println(\"buzz\")\n} else {\n    // otherwise, we print the number.\n    println(x)\n}\n```\n\n- Start all comments (including KDoc) with a space after the first symbol (`//`, `/*`, `/**` and `*`)\n\n**Valid example:**\n\n```kotlin\nval x = 0  // this is a comment\n```\n\n#### <a name=\"r2.4.2\"></a> 2.4.2 Do not comment on unused code blocks\n\nDo not comment on unused code blocks, including imports. Delete these code blocks immediately.\nA code is not used to store history. Git, svn, or other VCS tools should be used for this purpose.\nUnused imports increase the coupling of the code and are not conducive to maintenance. The commented out code cannot be appropriately maintained.\nIn an attempt to reuse the code, there is a high probability that you will introduce defects that are easily missed.\nThe correct approach is to delete the unnecessary code directly and immediately when it is not used anymore.\nIf you need the code again, consider porting or rewriting it as changes could have occurred since you first commented on the code. \n\n#### <a name=\"r2.4.3\"></a>2.4.3 Code delivered to the client should not contain TODO/FIXME comments\n\nThe code officially delivered to the client typically should not contain TODO/FIXME comments.\n`TODO` comments are typically used to describe modification points that need to be improved and added. For example, refactoring FIXME comments are typically used to describe known defects and bugs that will be subsequently fixed and are not critical for an application.\nThey should all have a unified style to facilitate unified text search processing.\n\n**Example:**\n\n```kotlin\n// TODO(<author-name>): Jira-XXX - support new json format\n// FIXME: Jira-XXX - fix NPE in this code block\n```\n\nAt a version development stage, these annotations can be used to highlight the issues in the code, but all of them should be fixed before a new product version is released.\n"
  },
  {
    "path": "info/guide/guide-chapter-3.md",
    "content": "# <a name=\"c3\"></a>3. General formatting (typesetting)\n<!-- =============================================================================== -->\n### <a name=\"c3.1\"></a> 3.1 File-related rules\nThis section describes the rules related to using files in your code.\n#### <a name=\"r3.1.1\"></a> 3.1.1 Avoid files that are too long\n\nIf the file is too long and complicated, it should be split into smaller files, functions, or modules. Files should not exceed 2000 lines (non-empty and non-commented lines).\nIt is recommended to horizontally or vertically split the file according to responsibilities or hierarchy of its parts.\nThe only exception to this rule is code generation - the auto-generated files that are not manually modified can be longer.\n\n#### <a name=\"r3.1.2\"></a> 3.1.2 Code blocks in the source file should be separated by one blank line\nA source file contains code blocks in the following order: copyright, package name, imports, and top-level classes. They should be separated by one blank line.\n\na) Code blocks should be in the following order:\n1.\tKdoc for licensed or copyrighted files\n2.\t`@file` annotation\n3.\tPackage name\n4.\tImport statements\n5.\tTop-class header and top-function header comments\n6.\tTop-level classes or functions\n\nb) Each of the preceding code blocks should be separated by a blank line.\n\nc) Import statements are alphabetically arranged, without using line breaks and wildcards ( wildcard imports - `*`).\n\nd) **Recommendation**: One `.kt` source file should contain only one class declaration, and its name should match the filename\n\ne) Avoid empty files that do not contain the code or contain only imports/comments/package name\n\nf) Unused imports should be removed\n#### <a name=\"r3.1.3\"></a> 3.1.3 Import statements order\n\nFrom top to bottom, the order is the following:\n1. Android\n2. Imports of packages used internally in your organization\n3. Imports from other non-core dependencies\n4. Java core packages\n5. kotlin stdlib\n\nEach category should be alphabetically arranged. Each group should be separated by a blank line. This style is compatible with  [Android import order](https://source.android.com/setup/contribute/code-style#order-import-statements).\n\n**Valid example**:\n```kotlin\nimport android.* // android\nimport androidx.* // android\nimport com.android.* // android\n\nimport com.your.company.* // your company's libs\nimport your.company.* // your company's libs\n\nimport com.fasterxml.jackson.databind.ObjectMapper // other third-party dependencies\nimport org.junit.jupiter.api.Assertions\n\nimport java.io.IOException // java core packages\nimport java.net.URL\n\nimport kotlin.system.exitProcess  // kotlin standard library\nimport kotlinx.coroutines.*  // official kotlin extension library\n```\n\n#### <a name=\"r3.1.4\"></a> 3.1.4 Order of declaration parts of class-like code structures\nThe declaration parts of class-like code structures (class, interface, etc.) should be in the following order: compile-time constants (for objects), class properties, late-init class properties, init-blocks, constructors, public methods, internal methods, protected methods, private methods, and companion object. Blank lines should separate their declaration.\nNotes:\n1.\tThere should be no blank lines between properties with the following **exceptions**: when there is a comment before a property on a separate line or annotations on a separate line.\n2.\tProperties with comments/Kdoc should be separated by a newline before the comment/Kdoc.\n3.\tEnum entries and constant properties (`const val`) in companion objects should be alphabetically arranged.\n\nThe declaration part of a class or interface should be in the following order:\n- Compile-time constants (for objects)\n- Properties\n- Late-init class properties\n- Init-blocks\n- Constructors\n- Methods or nested classes. Put nested classes next to the code they are used by.\nIf the classes are meant to be used externally, and are not referenced inside the class, put them after the companion object.\n- Companion object\n\n**Exception:**\nAll variants of a `private val` logger should be placed at the beginning of the class (`private val log`, `LOG`, `logger`, etc.).\n\n#### <a name=\"r3.1.5\"></a> 3.1.5 Order of declaration of top-level code structures\nKotlin allows several top-level declaration types: classes, objects, interfaces, properties and functions.\nWhen declaring more than one class or zero classes (e.g. only functions), as per rule [2.2.1](#r2.2.1), you should document the whole file in the header KDoc.\nWhen declaring top-level structures, keep the following order:\n1. Top-level constants and properties (following same order as properties inside a class: `const val`,`val`, `lateinit var`, `var`)\n2. Type aliases (grouped by their visibility modifiers)\n2. Interfaces, classes and objects (grouped by their visibility modifiers)\n3. Extension functions\n4. Other functions\n\n**Note**:\nExtension functions shouldn't have receivers declared in the same file according to [rule 6.2.3](#r6.2.3)\n\nValid example:\n```kotlin\npackage com.saveourtool.diktat.example\n\nconst val CONSTANT = 42\n\nval topLevelProperty = \"String constant\"\n\ninternal typealias ExamplesHandler = (IExample) -> Unit\n\ninterface IExample\n\nclass Example : IExample\n\nprivate class Internal\n\nfun Other.asExample(): Example { /* ... */ }\n\nprivate fun Other.asInternal(): Internal { /* ... */ }\n\nfun doStuff() { /* ... */ }\n```\n\n**Note**:\nkotlin scripts (.kts) allow arbitrary code to be placed on the top level. When writing kotlin scripts, you should first declare all properties, classes\nand functions. Only then you should execute functions on top level. It is still recommended wrapping logic inside functions and avoid using top-level statements\nfor function calls or wrapping blocks of code in top-level scope functions like `run`.\n\nExample:\n```kotlin\n/* class declarations */\n/* function declarations */\nrun {\n    // call functions here\n}\n```\n\n<!-- =============================================================================== -->\n### <a name=\"c3.2\"></a> 3.2 Braces\nThis section describes the general rules of using braces in your code.\n#### <a name=\"r3.2.1\"></a> 3.2.1 Using braces in conditional statements and loop blocks\n\nBraces should always be used in `if`, `else`, `for`, `do`, and `while` statements, even if the program body is empty or contains only one statement. In special Kotlin `when` statements, you do not need to use braces for single-line statements.\n\n**Valid example:**\n\n```kotlin\nwhen (node.elementType) {\n    FILE -> {\n        checkTopLevelDoc(node)\n        checkSomething()\n     }\n    CLASS -> checkClassElements(node)\n}\n```\n**Exception:** The only exception is ternary operator in Kotlin (a single line `if () <> else <>` )\n\n**Invalid example:**\n\n```kotlin\nval value = if (string.isEmpty())  // WRONG!\n                0\n            else\n                1\n```\n\n**Valid example**:\n\n```kotlin\nval value = if (string.isEmpty()) 0 else 1  // Okay\n```\n\n```kotlin\nif (condition) {\n    println(\"test\")\n} else {\n    println(0)\n}\n```\n\n#### <a name=\"r3.2.2\"></a> 3.2.2  Opening braces are placed at the end of the line in *non-empty* blocks and block structures\nFor *non-empty* blocks and block structures, the opening brace is placed at the end of the line.\nFollow the K&R style (1TBS or OTBS) for *non-empty* code blocks with braces:\n- The opening brace and first line of the code block are on the same line.\n- The closing brace is on its own new line.\n- The closing brace can be followed by a newline character. The only exceptions are `else`, `finally`, and `while` (from `do-while` statement), or `catch` keywords.\nThese keywords should not be split from the closing brace by a newline character.\n\n**Exception cases**:\n\n1) For lambdas, there is no need to put a newline character after the first (function-related) opening brace. A newline character should appear only after an arrow (`->`) (see [point 5 of Rule 3.6.2](#r3.6.2)).\n\n```kotlin\narg.map { value ->\n    foo(value)\n}\n```\n\n2) for `else`/`catch`/`finally`/`while` (from `do-while` statement) keywords closing brace should stay on the same line:\n ```kotlin\ndo {\n    if (true) {\n        x++\n    } else {\n        x--\n    }\n} while (x > 0)\n```\n\n**Valid example:**\n\n ```kotlin\n        return arg.map { value ->\n            while (condition()) {\n                method()\n            }\n            value\n        }\n\n        return MyClass() {\n            @Override\n              fun method() {\n                if (condition()) {\n                    try {\n                        something()\n                    } catch (e: ProblemException) {\n                        recover()\n                    }\n                } else if (otherCondition()) {\n                    somethingElse()\n                } else {\n                    lastThing()\n                }\n            }\n        }\n ```\n\n<!-- =============================================================================== -->\n### <a name=\"c3.3\"></a> 3.3 Indentation\n\nOnly spaces are permitted for indentation, and each indentation should equal `four spaces` (tabs are not permitted).\nIf you prefer using tabs, simply configure them to change to spaces in your IDE automatically.\nThese code blocks should be indented if they are placed on the new line, and the following conditions are met:\n-\tThe code block is placed immediately after an opening brace.\n-\tThe code block is placed after each operator, including the assignment operator (`+`/`-`/`&&`/`=`/etc.)\n-\tThe code block is a call chain of methods:\n```kotlin\nsomeObject\n    .map()\n    .filter()\n```\n-  The code block is placed immediately after the opening parenthesis.\n-  The code block is placed immediately after an arrow in lambda:\n\n ```kotlin\narg.map { value ->\n    foo(value)\n}\n```\n\n**Exceptions**:\n1.\tArgument lists: \\\na) Eight spaces are used to indent argument lists (both in declarations and at call sites). \\\nb) Arguments in argument lists can be aligned if they are on different lines.\n\n2.\tEight spaces are used if there is a newline after any binary operator.\n\n3.\tEight spaces are used for functional-like styles when the newline is placed before the dot.\n\n4.\tSupertype lists: \\\na) Four spaces are used if the colon before the supertype list is on a new line. \\\nb) Four spaces are used before each supertype, and eight spaces are used if the colon is on a new line.\n\n**Note:** there should be an indentation after all statements such as `if`, `for`, etc. However, according to this code style, such statements require braces.\n\n```kotlin\nif (condition)\n    foo()\n```\n\n**Exceptions**:\n- When breaking the parameter list of a method/class constructor, it can be aligned with `8 spaces`. A parameter that was moved to a new line can be on the same level as the previous argument:\n\n```kotlin\nfun visit(\n        node: ASTNode,\n        autoCorrect: Boolean,\n        params: KtLint.ExperimentalParams,\n        emit: (offset: Int, errorMessage: String, canBeAutoCorrected: Boolean) -> Unit\n) {\n}\n```\n\n- Such operators as `+`/`-`/`*` can be indented with `8 spaces`:\n\n```kotlin\nval abcdef = \"my split\" +\n                \" string\"\n```\n\n- Opening and closing quotes in multiline string with [`trimMargin()`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.text/trim-margin.html) or [`trimIndent()`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.text/trim-indent.html) method should have the same indentation:\n\n```kotlin\nlintMethod(\n            \"\"\"\n                    |val q = 1\n                    |\n            \"\"\".trimMargin()\n    )\n```\n\n- A list of supertypes should be indented with `4 spaces` if they are on different lines or with `8 spaces` if the leading colon is also on a separate line\n\n```kotlin\nclass A :\n    B()\n\nclass A\n    :\n        B()\n```\n\n<!-- =============================================================================== -->\n### <a name=\"c3.4\"></a> 3.4 Empty blocks\n\nAvoid empty blocks, and ensure braces start on a new line. An empty code block can be closed immediately on the same line and the next line. However, a newline is recommended between opening and closing braces `{}` (see the examples below.)\n\nGenerally, empty code blocks are prohibited; using them is considered a bad practice (especially for catch block).\nThey are appropriate for overridden functions, when the base class's functionality is not needed in the class-inheritor, for lambdas used as a function and for empty function in implementation of functional interface.\n```kotlin\noverride fun foo() {\n}\n```\n\n**Valid examples** (note once again that generally empty blocks are prohibited):\n\n```kotlin\nfun doNothing() {}\n\nfun doNothingElse() {\n}\n\nfun foo(bar: () -> Unit = {})\n```\n\n**Invalid examples:**\n```kotlin\ntry {\n  doSomething()\n} catch (e: Some) {}\n```\n\nUse the following valid code instead:\n```kotlin\ntry {\n   doSomething()\n} catch (e: Some) {\n}\n```\n\n<!-- =============================================================================== -->\n### <a name=\"c3.5\"></a> 3.5 Line length\n\nLine length should be less than 120 symbols. Otherwise, it should be split.\n\nif the initializer of a `complex property` is too long, it should be split into multiple lines using the operators grouped in the following precedence order:\n1. Logic Binary Expression (`&&` , `||`)\n2. Comparison Binary Expression (`>` , `<` , `==` , `>=` , `<=` , `!=`, `===`, `!==`)\n3. Other types (Arithmetical and Bitwise operation) (`+` , `-` , `*` , `/` , `%` , `>>` , `<<` , `&` , `|` , `~` , `^` , `>>>` , `<<<` , `*=` , `+=` , `-=` , `/=` , `%=` , `++` , `--` , `in` , `!in` etc)\n\n**Invalid example:**\n```kotlin\nval complexProperty = 1 + 2 + 3 + 4\n```\n**Valid example:**\n```kotlin\nval complexProperty = 1 + 2 +\n    3 + 4\n```\n\n**Invalid example:**\n```kotlin\nval complexProperty = (1 + 2 + 3 > 0) && ( 23 * 4 > 10 * 6)\n```\n**Valid example:**\n```kotlin\nval complexProperty = (1 + 2 + 3 > 0) &&\n    (23 * 4 > 10 * 6)\n```\n\nA long expression which should be split into two lines before the `Elvis Operator` (`?:`):\n\n**Invalid example:**\n```kotlin\nval value = first ?: second\n```\n\n**Valid example:**\n```kotlin\nval value = first\n    ?: second\n```\n\nA long line in a `Dot Qualified Expression` or a `Safe Access Expression`:\n\n**Invalid example:**\n```kotlin\nval value = This.Is.A.Very.Long.Dot.Qualified.Expression\n```\n**Valid example:**\n```kotlin\nval value = This.Is.A.Very.Long\n    .Dot.Qualified.Expression\n```\n\n**Invalid example:**\n```kotlin\nval value = This.Is?.A?.Very?.Long?.Safe?.Access?.Expression\n```\n**Valid example:**\n```kotlin\nval value = This.Is?.A?.Very?.Long\n    ?.Safe?.Access?.Expression\n```\n\nA long list of `function call arguments`:\n\n**Invalid example:**\n```kotlin\nval result1 = ManyParamInFunction(firstArgument, secondArgument, thirdArgument, fourthArgument, fifthArguments)\n```\n**Valid example:**\n```kotlin\nval result1 = ManyParamInFunction(firstArgument,\n secondArgument, thirdArgument, fourthArgument,\n fifthArguments)\n```\n\nIf an `annotation` is too long, it also should be split:\n\n**Invalid example:**\n```kotlin\n@Query(value = \"select * from table where age = 10\", nativeQuery = true)\nfun foo() {}\n```\n**Valid example:**\n```kotlin\n@Query(\n    value = \"select * from table where age = 10\",\n    nativeQuery = true)\nfun foo() {}\n```\n\nA long one line `function` should be split:\n\n**Invalid example:**\n```kotlin\nfun foo() = goo().write(\"TooLong\")\n```\n**Valid example:**\n```kotlin\nfun foo() =\n    goo().write(\"TooLong\")\n```\n\nA `long binary expression` should be split into multiple lines using the operators grouped in the following precedence:\n1. Logic Binary Expression (`&&` , `||`)\n2. Comparison Binary Expression (`>` , `<` , `==` , `>=` , `<=` , `!=`, `===`, `!==`)\n3. Other types (Arithmetical and Bitwise operation) (`+` , `-` , `*` , `/` , `%` , `>>` , `<<` , `&` , `|` , `~` , `^` , `>>>` , `<<<` , `*=` , `+=` , `-=` , `/=` , `%=` , `++` , `--` , `in` , `!in` etc)\n\n**Invalid example:**\n```kotlin\nif (( x >  100) || y < 100 && !isFoo()) {}\n```\n\n**Valid example:**\n```kotlin\nif (( x >  100) ||\n    y < 100 && !isFoo()) {}\n```\n\nA long `string template` should be split into several lines:\n\n**Invalid example:**\n```kotlin\nval nameString = \"This is a very long string template\"\n```\n\n**Valid example:**\n```kotlin\nval nameString = \"This is a very long\" +\n        \" string template\"\n```\n\nA long `lambda argument` should be split:\n\n**Invalid example:**\n```kotlin\nval variable = a?.filter { it.elementType == IDENTIFIER } ?: null\n```\n\n**Valid example:**\n```kotlin\nval variable = a?.filter {\n    it.elementType == IDENTIFIER\n} ?: null\n```\n\nA long `when-expression` body spanning only a single line should be split:\n\n**Invalid example:**\n```kotlin\nwhen (argument) {\n    true -> long.argument.whenEntry\n}\n```\n**Valid example:**\n```kotlin\nwhen (argument) {\n    true -> {\n        long.argument.whenEntry\n    }\n}\n```\n\nIf none of the above examples are suitable but a code fragment is a property declaration which needs to be split into multiple lines, then the property initializer can be moved into a separate line:\n\n**Invalid example:**\n```kotlin\nval element = veryLongNameFunction(firstParam)\n```\n**Valid example:**\n```kotlin\nval element =\n    veryLongNameFunction(firstParam)\n```\n\nAn `eol comment` also can be split, but it depends on comment location.\nIf the comment shares the same line with code, it should be moved to the line above:\n\n**Invalid example:**\n```kotlin\nfun foo() {\n    val name = \"Nick\" // this comment is too long\n}\n```\n**Valid example:**\n```kotlin\nfun foo() {\n    // this comment is too long\n    val name = \"Nick\"\n}\n```\n\nBut if this comment is on new line - it should be split to several lines:\n\n**Invalid example:**\n```kotlin\n// This comment is too long. It should be on two lines.\nfun foo() {}\n```\n\n**Valid example:**\n```kotlin\n// This comment is too long.\n// It should be on two lines.\nfun foo() {}\n```\n\nThe international code style prohibits `non-Latin` (`non-ASCII`) symbols. (See [Identifiers](#r1.1.1)) However, if you still intend on using them, follow\nthe following convention:\n\n- One wide character occupies the width of two narrow characters.\nThe \"wide\" and \"narrow\" parts of a character are defined by its [east Asian width Unicode attribute](https://unicode.org/reports/tr11/).\nTypically, narrow characters are also called \"half-width\" characters.\nAll characters in the ASCII character set include letters (such as `a, A`), numbers (such as `0, 3`), and punctuation spaces (such as `,` , `{`), all of which are narrow characters.\nWide characters are also called \"full-width\" characters. Chinese characters (such as `中, 文`), Chinese punctuation (`，` , `；` ), full-width letters and numbers (such as `Ａ、３`) are \"full-width\" characters.\nEach one of these characters represents two narrow characters.\n\n- Any line that exceeds this limit (`120 narrow symbols`) should be wrapped, as described in the [Newline section](#c3.5).\n\n**Exceptions:**\n\n1.\tThe long URL or long JSON method reference in KDoc.\n2.\tThe `package` and `import` statements.\n3.\tThe command line in the comment, enabling it to be cut and pasted into the shell for use.\n\n<!-- =============================================================================== -->\n### <a name=\"c3.6\"></a> 3.6 Line breaks (newlines)\nThis section contains the rules and recommendations on using line breaks.\n#### <a name=\"r3.6.1\"></a> 3.6.1 Each line can have a maximum of one statement\nEach line can have a maximum of one code statement. This recommendation prohibits the use of code with `;` because it decreases code visibility.\n\n**Invalid example:**\n```kotlin\nval a = \"\"; val b = \"\"\n```\n\n**Valid example:**\n```kotlin\nval a = \"\"\nval b = \"\"\n```\n\n#### <a name=\"r3.6.2\"></a> 3.6.2 Rules for line-breaking\n\n1) Unlike Java, Kotlin allows you not to put a semicolon (`;`) after each statement separated by a newline character.\n    There should be no redundant semicolon at the end of the lines.\n\nWhen a newline character is needed to split the line, it should be placed after such operators as `&&`/`||`/`+`/etc. and all infix functions (for example, `xor`).\nHowever, the newline character should be placed before operators such as `.`, `?.`, `?:`, and `::`.\n\nNote that all comparison operators, such as `==`, `>`, `<`, should not be split.\n\n**Invalid example**:\n```kotlin\n     if (node !=\n             null && test != null) {}\n```\n\n**Valid example**:\n```kotlin\n         if (node != null &&\n                 test != null) {\n         }\n```\n\n**Note:** You need to follow the functional style, meaning each function call in a chain with `.` should start at a new line if the chain of functions contains more than one call:\n```kotlin\n  val value = otherValue!!\n          .map { x -> x }\n          .filter {\n              val a = true\n              true\n          }\n          .size\n```\n**Note:** The parser prohibits the separation of the `!!` operator from the value it is checking.\n\n**Exception**: If a functional chain is used inside the branches of a ternary operator, it does not need to be split with newlines.\n\n**Valid example**:\n```kotlin\nif (condition) list.map { foo(it) }.filter { bar(it) } else list.drop(1)\n```\n\n**Note:** If dot qualified expression is inside condition or passed as an argument - it should be replaced with new variable.\n\n**Invalid example**:\n```kotlin\n if (node.treeParent.treeParent?.treeParent.findChildByType(IDENTIFIER) != null) {}\n```\n\n**Valid example**:\n```kotlin\n        val grandIdentifier = node\n            .treeParent\n            .treeParent\n            ?.treeParent\n            .findChildByType(IDENTIFIER)\n        if (grandIdentifier != null) {}\n```\n**Another valid example**:\n```kotlin\n        val grandIdentifier = node.treeParent\n            .treeParent\n            ?.treeParent\n            .findChildByType(IDENTIFIER)\n        if (grandIdentifier != null) {}\n```\n\n2)\tNewlines should be placed after the assignment operator (`=`).\n3)\tIn function or class declarations, the name of a function or constructor should not be split by a newline from the opening brace `(`.\n    A brace should be placed immediately after the name without any spaces in declarations or at call sites.\n4)\tNewlines should be placed right after the comma (`,`).\n5)\tIf a lambda statement contains more than one line in its body, a newline should be placed after an arrow if the lambda statement has explicit parameters.\n    If it uses an implicit parameter (`it`), the newline character should be placed after the opening brace (`{`).\n    The following examples illustrate this rule:\n\n\n**Invalid example:**\n```kotlin\n    value.map { name -> foo()\n        bar()\n    }\n```\n\n**Valid example:**\n```kotlin\nvalue.map { name ->\n    foo()\n    bar()\n}\n\nval someValue = { node:String -> node }\n```\n\n6)  When a function body consists of only a single expression, it can be re-written as an [_expression function_](https://kotlinlang.org/docs/reference/functions.html#single-expression-functions).\n\nInstead of:\n```kotlin\noverride fun toString(): String { return \"hi\" }\n```\nuse:\n```kotlin\noverride fun toString() = \"hi\"\n```\n\n7)  If an argument list in a function declaration (including constructors) or function call contains more than two arguments, these arguments should be split by newlines in the following style.\n\n**Valid example:**\n ```kotlin\nclass Foo(val a: String,\n          b: String,\n          val c: String) {\n}\n\nfun foo(\n        a: String,\n        b: String,\n        c: String\n) {\n\n}\n ```\n\nIf and only if the first parameter is on the same line as an opening parenthesis, all parameters can be horizontally aligned by the first parameter.\nOtherwise, there should be a line break after an opening parenthesis.\n\nKotlin 1.4 introduced a trailing comma as an optional feature, so it is generally recommended to place all parameters on a separate line\nand append [trailing comma](https://kotlinlang.org/docs/reference/whatsnew14.html#trailing-comma).\nIt makes the resolving of merge conflicts easier.\n\n**Valid example:**\n ```kotlin\nfun foo(\n        a: String,\n        b: String,\n) {\n\n}\n ```\n\nsame should be done for function calls/constructor arguments/e.t.c\n\nKotlin supports trailing commas in the following cases:\n\nEnumerations\nValue arguments\nClass properties and parameters\nFunction value parameters\nParameters with optional type (including setters)\nIndexing suffix\nLambda parameters\nwhen entry\nCollection literals (in annotations)\nType arguments\nType parameters\nDestructuring declarations\n\n8) If the supertype list has more than two elements, they should be separated by newlines.\n\n**Valid example:**\n```kotlin\nclass MyFavouriteVeryLongClassHolder :\n    MyLongHolder<MyFavouriteVeryLongClass>(),\n    SomeOtherInterface,\n    AndAnotherOne { }\n```\n\n<!-- =============================================================================== -->\n### <a name=\"c3.7\"></a> 3.7 Using blank lines\n\nReduce unnecessary blank lines and maintain a compact code size. By reducing unnecessary blank lines, you can display more code on one screen, which improves code readability.\n- Blank lines should separate content based on relevance and should be placed between groups of fields, constructors, methods, nested classes, `init` blocks, and objects (see [3.1.2](#r3.1.2)).\n- Do not use more than one line inside methods, type definitions, and initialization expressions.\n- Generally, do not use more than two consecutive blank lines in a row.\n- Do not put newlines in the beginning or end of code blocks with curly braces.\n\n**Valid example:**\n```kotlin\nfun baz() {\n\n    doSomething()  // No need to add blank lines at the beginning and end of the code block\n    // ...\n\n}\n```\n\n<!-- =============================================================================== -->\n### <a name=\"c3.8\"></a> 3.8 Horizontal space\nThis section describes general rules and recommendations for using spaces in the code.\n#### <a name=\"r3.8.1\"></a> 3.8.1: Usage of whitespace for code separation\n\nFollow the recommendations below for using space to separate keywords:\n\n**Note:** These recommendations are for cases where symbols are located on the same line. However, in some cases, a line break could be used instead of a space.\n\n1.  Separate keywords (such as `if`, `when`, `for`) from the opening parenthesis with single whitespace.\n    The only exception is the `constructor` keyword, which should not be separated from the opening parenthesis.\n\n2.  Separate keywords like `else` or `try` from the opening brace (`{`) with single whitespace.\n    If `else` is used in a ternary-style statement without braces, there should be a single space between `else` and the statement after: `if (condition) foo() else bar()`\n\n3.  Use a **single** whitespace before all opening braces (`{`). The only exception is the passing of a lambda as a parameter inside parentheses:\n ```kotlin\n     private fun foo(a: (Int) -> Int, b: Int) {}\n     foo({x: Int -> x}, 5) // no space before '{'\n ```\n\n4.  Single whitespace should be placed on both sides of binary operators. This also applies to operator-like symbols.\n    For example:\n\n - A colon in generic structures with the `where` keyword:  `where T : Type`\n - Arrow in lambdas: `(str: String) -> str.length()`\n\n**Exceptions:**\n\n- Two colons (`::`) are written without spaces:\\\n  `Object::toString`\n- The dot separator (`.`) that stays on the same line with an object name:\\\n  `object.toString()`\n- Safe access modifiers `?.` and `!!` that stay on the same line with an object name:\\\n  `object?.toString()`\n- Operator `..` for creating ranges:\\\n  `1..100`\n\n5.  Use spaces after (`,`), (`:`), and (`;`), except when the symbol is at the end of the line.\n    However, note that this code style prohibits the use of (`;`) in the middle of a line ([see 3.3.2](#r3.2.2)).\n    There should be no whitespaces at the end of a line.\n    The only scenario where there should be no space after a colon is when the colon is used in the annotation to specify a use-site target (for example, `@param:JsonProperty`).\n    There should be no spaces before `,` , `:` and `;`.\n\n    **Exceptions** for spaces and colons:\n\n    - When `:` is used to separate a type and a supertype, including an anonymous object (after object keyword)\n    - When delegating to a superclass constructor or different constructor of the same class\n\n**Valid example:**\n```kotlin\n  abstract class Foo<out T : Any> : IFoo { }\n\n  class FooImpl : Foo() {\n      constructor(x: String) : this(x) { /*...*/ }\n\n      val x = object : IFoo { /*...*/ }\n  }\n```\n\n6. There should be *only one space* between the identifier and its type: `list: List<String>`\nIf the type is nullable, there should be no space before `?`.\n\n7. When using `[]` operator (`get/set`) there should be **no** spaces between identifier and `[` : `someList[0]`.\n\n8. There should be no space between a method or constructor name (both at declaration and at call site) and a parenthesis:\n   `foo() {}`. Note that this sub-rule is related only to spaces; the rules for whitespaces are described in [see 3.6.2](#r3.6.2).\n    This rule does not prohibit, for example, the following code:\n```kotlin\nfun foo\n(\n    a: String\n)\n```\n\n9. Never put a space after `(`, `[`, `<` (when used as a bracket in templates) or before `)`, `]`, `>` (when used as a bracket in templates).\n\n10. There should be no spaces between a prefix/postfix operator (like `!!` or `++`) and its operand.\n\n#### <a name=\"r3.8.2\"></a> 3.8.2: No spaces for horizontal alignment\n\n*Horizontal alignment* refers to aligning code blocks by adding space to the code. Horizontal alignment should not be used because:\n\n- When modifying code, it takes much time for new developers to format, support, and fix alignment issues.\n- Long identifier names will break the alignment and lead to less presentable code.\n- There are more disadvantages than advantages in alignment. To reduce maintenance costs, misalignment (???) is the best choice.\n\nRecommendation: Alignment only looks suitable for `enum class`, where it can be used in table format to improve code readability:\n```kotlin\nenum class Warnings(private val id: Int, private val canBeAutoCorrected: Boolean, private val warn: String) : Rule {\n    PACKAGE_NAME_MISSING         (1, true,  \"no package name declared in a file\"),\n    PACKAGE_NAME_INCORRECT_CASE  (2, true,  \"package name should be completely in a lower case\"),\n    PACKAGE_NAME_INCORRECT_PREFIX(3, false, \"package name should start from the company's domain\")\n    ;\n}\n```\n\n**Valid example:**\n ```kotlin\n private val nr: Int // no alignment, but looks fine\n private var color: Color // no alignment\n ```\n\n**Invalid example**:\n ```kotlin\n private val    nr: Int    // aligned comment with extra spaces\n private val color: Color  // alignment for a comment and alignment for identifier name\n ```\n\n<!-- =============================================================================== -->\n### <a name=\"c3.9\"></a> 3.9 Enumerations\nEnum values are separated by a comma and line break, with ';' placed on the new line.\n\n1) The comma and line break characters separate enum values. Put `;` on the new line:\n```kotlin\nenum class Warnings {\n    A,\n    B,\n    C,\n    ;\n}\n```\n\nThis will help to resolve conflicts and reduce the number of conflicts during merging pull requests.\nAlso, use [trailing comma](https://kotlinlang.org/docs/reference/whatsnew14.html#trailing-comma).\n\n2) If the enum is simple (no properties, methods, and comments inside), you can declare it in a single line:\n```kotlin\nenum class Suit { CLUBS, HEARTS, SPADES, DIAMONDS }\n```\n\n3) Enum classes take preference (if it is possible to use it). For example, instead of two boolean properties:\n\n```kotlin\nval isCelsius = true\nval isFahrenheit = false\n```\n\nuse enum class:\n\n```kotlin\nenum class TemperatureScale { CELSIUS, FAHRENHEIT }\n```\n\n- The variable value only changes within a fixed range and is defined with the enum type.\n- Avoid comparison with magic numbers of `-1, 0, and 1`; use enums instead.\n\n```kotlin\nenum class ComparisonResult {\n    ORDERED_ASCENDING,\n    ORDERED_SAME,\n    ORDERED_DESCENDING,\n    ;\n}\n```\n\n<!-- =============================================================================== -->\n### <a name=\"c3.10\"></a> 3.10 Variable declaration\nThis section describes rules for the declaration of variables.\n#### <a name=\"r3.10.1\"></a> 3.10.1 Declare one variable per line\n\nEach property or variable must be declared on a separate line.\n\n**Invalid example**:\n```kotlin\nval n1: Int; val n2: Int\n```\n\n#### <a name=\"r3.10.2\"></a> 3.10.2 Variables should be declared near the line where they are first used\nDeclare local variables close to the point where they are first used to minimize their scope. This will also increase the readability of the code.\nLocal variables are usually initialized during their declaration or immediately after.\nThe member fields of the class should be declared collectively (see [Rule 3.1.2](#r3.1.2) for details on the class structure).\n\n<!-- =============================================================================== -->\n### <a name=\"c3.11\"></a> 3.11 'When' expression\n\nThe `when` statement must have an 'else' branch unless the condition variable is enumerated or a sealed type.\nEach `when` statement should contain an `else` statement group, even if it does not contain any code.\n\n**Exception:** If 'when' statement of the `enum or sealed` type contains all enum values, there is no need to have an \"else\" branch.\nThe compiler can issue a warning when it is missing.\n\n<!-- =============================================================================== -->\n### <a name=\"c3.12\"></a> 3.12 Annotations\nThis section contains recommendations regarding annotations.\n#### <a name=\"r3.12.1\"></a> 3.12.1 Whitespaces and newlines for annotations\nEach annotation applied to a class, method or constructor should be placed on its own line. Consider the following examples:\n1. Annotations applied to the class, method or constructor are placed on separate lines (one annotation per line).\n\n**Valid example**:\n```kotlin\n@MustBeDocumented\n@CustomAnnotation\nfun getNameIfPresent() { /* ... */ }\n```\n\n2. A single annotation should be on the same line as the code it is annotating.\n\n**Valid example**:\n```kotlin\n@CustomAnnotation class Foo {}\n```\n\n3. Multiple annotations applied to a field or property can appear on the same line as the corresponding field.\n\n**Valid example**:\n```kotlin\n@MustBeDocumented @CustomAnnotation val loader: DataLoader\n```\n#### <a name=\"r3.12.2\"></a> 3.12.2 Preview annotation\n`@Preview` (Jetpack Compose) functions should end with 'Preview' suffix and are also be private\n\n**Valid example**:\n```kotlin\n@Preview\n@Composable\nprivate fun BannerPreview() {}\n```\n\n\n<!-- =============================================================================== -->\n### <a name=\"c3.13\"></a> 3.13 Block comments\n\nBlock comments should be placed at the same indentation level as the surrounding code. See examples below.\n\n**Valid example**:\n\n ```kotlin\nclass SomeClass {\n     /*\n      * This is\n      * okay\n      */\n      fun foo() {}\n}\n ```\n\n**Note**: Use `/*...*/` block comments to enable automatic formatting by IDEs.\n\n<!-- =============================================================================== -->\n### <a name=\"c3.14\"></a> 3.14 Modifiers and constant values\nThis section contains recommendations regarding modifiers and constant values.\n#### <a name=\"r3.14.1\"></a> 3.14.1 Declaration with multiple modifiers\nIf a declaration has multiple modifiers, always follow the proper sequence.\n`Value` identifier supported in Kotlin 1.5\n**Valid sequence:**\n\n```kotlin\npublic / internal / protected / private\nexpect / actual\nfinal / open / abstract / sealed / const\nexternal\noverride\nlateinit\ntailrec\ncrossinline\nvararg\nsuspend\ninner\nout\nenum / annotation\ncompanion\nvalue / inline / noinline\nreified\ninfix\noperator\ndata\n```\n\n#### <a name=\"r3.14.2\"></a> 3.14.2: Separate long numerical values with an underscore\nAn underscore character should separate long numerical values.\n**Note:** Using underscores simplifies reading and helps to find errors in numeric constants.\n```kotlin\nval oneMillion = 1_000_000\nval creditCardNumber = 1234_5678_9012_3456L\nval socialSecurityNumber = 999_99_9999L\nval hexBytes = 0xFF_EC_DE_5E\nval bytes = 0b11010010_01101001_10010100_10010010\n```\n#### <a name=\"r3.14.3\"></a> 3.14.3: Magic number\nPrefer defining constants with clear names describing what the magic number means.\n**Valid example**:\n```kotlin\nclass Person() {\n    fun isAdult(age: Int): Boolean = age >= majority\n\n    companion object {\n        private const val majority = 18\n    }\n}\n```\n**Invalid example**:\n```kotlin\nclass Person() {\n    fun isAdult(age: Int): Boolean = age >= 18\n}\n```\n\n<!-- =============================================================================== -->\n### <a name=\"c3.15\"></a> 3.15 Strings\nThis section describes the general rules of using strings.\n\n#### <a name=\"r3.15.1\"></a> 3.15.1 Concatenation of Strings\nString concatenation is prohibited if the string can fit on one line. Use raw strings and string templates instead. Kotlin has significantly improved the use of Strings:\n[String templates](https://kotlinlang.org/docs/reference/basic-types.html#string-templates), [Raw strings](https://kotlinlang.org/docs/reference/basic-types.html#string-literals).\nTherefore, compared to using explicit concatenation, code looks much better when proper Kotlin strings are used for short lines, and you do not need to split them with newline characters.\n\n**Invalid example**:\n```kotlin\nval myStr = \"Super string\"\nval value = myStr + \" concatenated\"\n```\n\n**Valid example**:\n```kotlin\nval myStr = \"Super string\"\nval value = \"$myStr concatenated\"\n```\n\n#### <a name=\"r3.15.2\"></a> 3.15.2 String template format\n**Redundant curly braces in string templates**\n\nIf there is only one variable in a string template, there is no need to use such a template. Use this variable directly.\n**Invalid example**:\n```kotlin\nval someString = \"${myArgument} ${myArgument.foo()}\"\n```\n\n**Valid example**:\n```kotlin\nval someString = \"$myArgument ${myArgument.foo()}\"\n```\n\n**Redundant string template**\n\nIn case a string template contains only one variable - there is no need to use the string template. Use this variable directly.\n\n**Invalid example**:\n```kotlin\nval someString = \"$myArgument\"\n```\n\n**Valid example**:\n```kotlin\nval someString = myArgument\n```\n\n<!-- =============================================================================== -->\n### <a name=\"c3.16\"></a> 3.16 Conditional Statements\nThis section describes the general rules related to the conditional statements.\n\n#### <a name=\"r3.16.1\"></a> 3.16.1 Collapsing redundant nested if-statements\nThe nested if-statements, when possible, should be collapsed into a single one\nby concatenating their conditions with the infix operator &&.\n\nThis improves the readability by reducing the number of the nested language constructs.\n\n#### Simple collapse\n\n**Invalid example**:\n```kotlin\nif (cond1) {\n    if (cond2) {\n        doSomething()\n    }\n}\n```\n\n**Valid example**:\n```kotlin\nif (cond1 && cond2) {\n    doSomething()\n}\n```\n\n#### Compound conditions\n\n**Invalid example**:\n```kotlin\nif (cond1) {\n    if (cond2 || cond3) {\n        doSomething()\n    }\n}\n```\n\n**Valid example**:\n```kotlin\nif (cond1 && (cond2 || cond3)) {\n    doSomething()\n}\n```\n#### <a name=\"r3.16.2\"></a> 3.16.2 Too complex conditions\nToo complex conditions should be simplified according to boolean algebra rules, if it is possible.\nThe following rules are considered when simplifying an expression:\n* boolean literals are removed (e.g. `foo() || false` -> `foo()`)\n* double negation is removed (e.g. `!(!a)` -> `a`)\n* expression with the same variable are simplified (e.g. `a && b && a` -> `a && b`)\n* remove expression from disjunction, if they are subset of other expression (e.g. `a || (a && b)` -> `a`)\n* remove expression from conjunction, if they are more broad than other expression (e.g. `a && (a || b)` -> `a`)\n* de Morgan's rule (negation is moved inside parentheses, i.e. `!(a || b)` -> `!a && !b`)\n\n**Valid example**\n```kotlin\nif (condition1 && condition2) {\n    foo()\n}\n```\n\n**Invalid example**\n```kotlin\nif (condition1 && condition2 && condition1) {\n    foo()\n}\n```\n\n<!-- =============================================================================== -->\n### <a name=\"c3.17\"></a> 3.17 Ranges\nThis section describes guidelines for working with ranges.\n\n#### <a name=\"r3.17.1\"></a> 3.17.1\nWhen creating a range with excluded upper boundary, instead of using range function with included upper boundary (`rangeTo` or `..`)\nit's preferred to use a range function with excluded upper boundary (`until`).\nInvalid example:\n```kotlin\n0..(a-1)\n```\nValid example:\n```kotlin\n0 until a\n```\n\nInstead of `rangeTo` function it's preferred to use `..` operator.\n\n<!-- =============================================================================== -->\n### <a name=\"c3.18\"></a> 3.18 Logging\nThis section describes the general rules of logging.\n\n#### <a name=\"r3.18.1\"></a> 3.18.1 Debug logging\nThe dedicated logging library should be used for logging purposes.\nNeed to try to avoid the following statements (assumption that it's a debug logging):\n```kotlin\nprint(\"I'M HERE\")\nprintln(\"test\")\n```\n\nAdditionally, need to avoid the following statements on Kotlin JS:\n```kotlin\nconsole.info(\"info test\")\nconsole.log(\"test\")\n```\n"
  },
  {
    "path": "info/guide/guide-chapter-4.md",
    "content": "# <a name=\"c4\"></a> 4. Variables and types\nThis section is dedicated to the rules and recommendations for using variables and types in your code.\n<!-- =============================================================================== -->\n### <a name=\"c4.1\"></a> 4.1 Variables\nThe rules of using variables are explained in the below topics.\n#### <a name=\"r4.1.1\"></a> 4.1.1 Do not use Float and Double types when accurate calculations are needed\nFloating-point numbers provide a good approximation over a wide range of values, but they cannot produce accurate results in some cases.\nBinary floating-point numbers are unsuitable for precise calculations because it is impossible to represent 0.1 or any other negative power of 10 in a `binary representation` with a finite length.\n\nThe following code example seems to be obvious: \n```kotlin\n    val myValue = 2.0 - 1.1\n    println(myValue)\n``` \n\nHowever, it will print the following value: `0.8999999999999999`\n\nTherefore, for precise calculations (for example, in finance or exact sciences), using such types as `Int`, `Long`, `BigDecimal`are recommended.\nThe `BigDecimal` type should serve as a good choice.\n\n**Invalid example**:\nFloat values containing more than six or seven decimal numbers will be rounded.\n ```kotlin\n val eFloat = 2.7182818284f // Float, will be rounded to 2.7182817\n ```\n\n**Valid example**: (when precise calculations are needed): \n ```kotlin\n    val income = BigDecimal(\"2.0\")\n    val expense = BigDecimal(\"1.1\")\n    println(income.subtract(expense)) // you will obtain 0.9 here\n ```\n\n#### <a name=\"r4.1.2\"></a> 4.1.2: Comparing numeric float type values\nNumeric float type values should not be directly compared with the equality operator (==) or other methods, such as `compareTo()` and `equals()`. Since floating-point numbers involve precision problems in computer representation, it is better to use `BigDecimal` as recommended in [Rule 4.1.1](#r4.1.1) to make accurate computations and comparisons. The following code describes these problems.\n\n**Invalid example**:\n ```kotlin\nval f1 = 1.0f - 0.9f\nval f2 = 0.9f - 0.8f\nif (f1 == f2) {\n    println(\"Expected to enter here\")\n} else {\n    println(\"But this block will be reached\")\n}\n\nval flt1 = f1;\nval flt2 = f2;\nif (flt1.equals(flt2)) {\n    println(\"Expected to enter here\")\n} else {\n    println(\"But this block will be reached\")\n} \n ```\n\n**Valid example**:\n\n```kotlin\nval foo = 1.03f\nval bar = 0.42f\nif (abs(foo - bar) > 1e-6f) {\n    println(\"Ok\")\n} else {\n    println(\"Not\")\n}\n```\n\n#### <a name=\"r4.1.3\"></a> 4.1.3 Try to use 'val' instead of 'var' for variable declaration [SAY_NO_TO_VAR]\n\nVariables with the `val` modifier are immutable (read-only).\nUsing `val` variables instead of `var` variables increases code robustness and readability.\nThis is because `var` variables can be reassigned several times in the business logic.\nHowever, in some scenarios with loops or accumulators, only `var`s are permitted.\n\n<!-- =============================================================================== -->\n### <a name=\"c4.2\"></a> 4.2 Types\nThis section provides recommendations for using types.\n#### <a name=\"r4.2.1\"></a> 4.2.1: Use Contracts and smart cast as much as possible\n\nThe Kotlin compiler has introduced [Smart Casts](https://kotlinlang.org/docs/reference/typecasts.html#smart-casts) that help reduce the size of code.\n\n**Invalid example**:\n```kotlin\n    if (x is String) {\n        print((x as String).length) // x was already automatically cast to String - no need to use 'as' keyword here\n    }\n```\n\n**Valid example**:\n```kotlin\n    if (x is String) {\n        print(x.length) // x was already automatically cast to String - no need to use 'as' keyword here\n    }\n```\n\nAlso, Kotlin 1.3 introduced [Contracts](https://kotlinlang.org/docs/reference/whatsnew13.html#contracts) that provide enhanced logic for smart-cast.\nContracts are used and are very stable in `stdlib`, for example:\n \n\n```kotlin\nfun bar(x: String?) {\n    if (!x.isNullOrEmpty()) {\n        println(\"length of '$x' is ${x.length}\") // smartcasted to not-null\n    }\n} \n```\n\nSmart cast and contracts are a better choice because they reduce boilerplate code and features forced type conversion.\n\n**Invalid example**:\n```kotlin\nfun String?.isNotNull(): Boolean = this != null\n\nfun foo(s: String?) {\n    if (s.isNotNull()) s!!.length // No smartcast here and !! operator is used\n}\n```\n\n**Valid example**:\n```kotlin\nfun foo(s: String?) {\n    if (s.isNotNull()) s.length // We have used a method with contract from stdlib that helped compiler to execute smart cast\n}\n```\n\n#### <a name=\"r4.2.2\"></a> 4.2.2: Try to use type alias to represent types making code more readable\n\nType aliases provide alternative names for existing types.\nIf the type name is too long, you can replace it with a shorter name, which helps to shorten long generic types.\nFor example, code looks much more readable if you introduce a `typealias` instead of a long chain of nested generic types.\nWe recommend using a `typealias` if the type contains **more than two** nested generic types and is longer than **25 chars**.\n\n**Invalid example**:\n```kotlin\nval b: MutableMap<String, MutableList<String>>\n```\n\n**Valid example**:\n```kotlin\ntypealias FileTable = MutableMap<String, MutableList<String>>\nval b: FileTable\n```\n\nYou can also provide additional aliases for function (lambda-like) types:\n```kotlin\ntypealias MyHandler = (Int, String, Any) -> Unit\n\ntypealias Predicate<T> = (T) -> Boolean\n```\n\n<!-- =============================================================================== -->\n### <a name=\"c4.3\"></a> 4.3 Null safety and variable declarations\nKotlin is declared as a null-safe programming language. However, to achieve compatibility with Java, it still supports nullable types.\n\n#### <a name=\"r4.3.1\"></a> 4.3.1: Avoid declaring variables with nullable types, especially from Kotlin stdlib\nTo avoid `NullPointerException` and help the compiler prevent Null Pointer Exceptions, avoid using nullable types (with `?` symbol).\n\n**Invalid example**:\n```kotlin \nval a: Int? = 0\n```\n\n**Valid example**:\n```kotlin \nval a: Int = 0\n```\n\nNevertheless, when using Java libraries extensively, you have to use nullable types and enrich the code with `!!` and `?` symbols.\nAvoid using nullable types for Kotlin stdlib (declared in [official documentation](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.collections/)). \nTry to use initializers for empty collections. For example, if you want to initialize a list instead of `null`, use `emptyList()`.\n\n**Invalid example**:\n```kotlin \nval a: List<Int>? = null \n```\n\n**Valid example**:\n```kotlin \nval a: List<Int> = emptyList()\n```\n\n#### <a name=\"r4.3.2\"></a> 4.3.2: Variables of generic types should have an explicit type declaration\nLike in Java, classes in Kotlin may have type parameters. To create an instance of such a class, we typically need to provide type arguments:\n\n```kotlin\nval myVariable: Map<Int, String> = emptyMap<Int, String>() \n```\n\nHowever, the compiler can inherit type parameters from the r-value (value assigned to a variable). Therefore, it will not force users to declare the type explicitly.\nThese declarations are not recommended because programmers would need to find the return value and understand the variable type by looking at the method.\n\n**Invalid example**:\n```kotlin\nval myVariable = emptyMap<Int, String>() \n```\n\n**Valid example**:\n```kotlin\nval myVariable: Map<Int, String> = emptyMap() \n```\n\n#### <a name=\"r4.3.3\"></a> 4.3.3 Null-safety\n\nTry to avoid explicit null checks (explicit comparison with `null`) \nKotlin is declared as [Null-safe](https://kotlinlang.org/docs/reference/null-safety.html) language.\nHowever, Kotlin architects wanted Kotlin to be fully compatible with Java; that's why the `null` keyword was also introduced in Kotlin. \n\nThere are several code-structures that can be used in Kotlin to avoid null-checks. For example: `?:`,  `.let {}`, `.also {}`, e.t.c\n\n**Invalid example:**\n```kotlin\n// example 1\nvar myVar: Int? = null\nif (myVar == null) {\n    println(\"null\")\n    return\n}\n\n// example 2\nif (myVar != null) {\n    println(\"not null\")\n    return\n}\n\n// example 3\nval anotherVal = if (myVar != null) {\n                     println(\"not null\")\n                     1\n                 } else {\n                     2\n                 }\n// example 4\nif (myVar == null) {\n    println(\"null\")\n} else {\n    println(\"not null\")\n}\n```\n\n**Valid example:**\n```kotlin\n// example 1\nvar myVar: Int? = null\nmyVar?: run {\n    println(\"null\")\n    return\n}\n\n// example 2\nmyVar?.let {\n    println(\"not null\")\n    return\n}\n\n// example 3\nval anotherVal = myVar?.also {\n                     println(\"not null\")\n                     1\n                 } ?: 2\n\n// example 4\nmyVar?.let {\n    println(\"not null\")\n} ?: run { println(\"null\") }\n```\n\n**Exceptions:**\n\nIn the case of complex expressions, such as multiple `else-if` structures or long conditional statements, there is common sense to use explicit comparison with `null`.\n\n**Valid examples:**\n\n```kotlin\nif (myVar != null) {\n    println(\"not null\")\n} else if (anotherCondition) {\n    println(\"Other condition\")\n}\n``` \n\n```kotlin\nif (myVar == null || otherValue == 5 && isValid) {}\n```\n\nPlease also note, that instead of using `require(a != null)` with a not null check - you should use a special Kotlin function called `requireNotNull(a)`.\n\n"
  },
  {
    "path": "info/guide/guide-chapter-5.md",
    "content": "# <a name=\"c5\"></a> 5. Functions\nThis section describes the rules of using functions in your code.\n<!-- =============================================================================== -->\n### <a name=\"c5.1\"></a> 5.1 Function design\nDevelopers can write clean code by gaining knowledge of how to build design patterns and avoid code smells.\nYou should utilize this approach, along with functional style, when writing Kotlin code.\nThe concepts behind functional style are as follows:\nFunctions are the smallest unit of combinable and reusable code.\nThey should have clean logic, **high cohesion**, and **low coupling** to organize the code effectively.\nThe code in functions should be simple and not conceal the author's original intentions.\n\nAdditionally, it should have a clean abstraction, and control statements should be used straightforwardly.\nThe side effects (code that does not affect a function's return value but affects global/object instance variables) should not be used for state changes of an object.\nThe only exceptions to this are state machines.\n\nKotlin is [designed](https://www.slideshare.net/abreslav/whos-more-functional-kotlin-groovy-scala-or-java) to support and encourage functional programming, featuring the corresponding built-in mechanisms.\nAlso, it supports standard collections and sequences feature methods that enable functional programming (for example, `apply`, `with`, `let`, and `run`), Kotlin Higher-Order functions, function types, lambdas, and default function arguments.\nAs [previously discussed](#r4.1.3), Kotlin supports and encourages the use of immutable types, which in turn motivates programmers to write pure functions that avoid side effects and have a corresponding output for specific input.\nThe pipeline data flow for the pure function comprises a functional paradigm. It is easy to implement concurrent programming when you have chains of function calls, where each step features the following characteristics:\n1.\tSimplicity\n2.\tVerifiability\n3.\tTestability\n4.\tReplaceability\n5.\tPluggability\n6.\tExtensibility\n7.\tImmutable results\n\nThere can be only one side effect in this data stream, which can be placed only at the end of the execution queue.\n\n#### <a name=\"r5.1.1\"></a> 5.1.1 Avoid functions that are too long\n\nThe function should be displayable on one screen and only implement one certain logic.\nIf a function is too long, it often means complex and could be split or simplified. Functions should consist of 30 lines (non-empty and non-comment) in total.\n\n**Exception:** Some functions that implement complex algorithms may exceed 30 lines due to aggregation and comprehensiveness.\nLinter warnings for such functions **can be suppressed**.\n\nEven if a long function works well, new problems or bugs may appear due to the function's complex logic once it is modified by someone else.\nTherefore, it is recommended to split such functions into several separate and shorter functions that are easier to manage.\nThis approach will enable other programmers to read and modify the code properly.\n#### <a name=\"r5.1.2\"></a> 5.1.2 Avoid deep nesting of function code blocks, limiting to four levels\n\nThe nesting depth of a function's code block is the depth of mutual inclusion between the code control blocks in the function (for example: if, for, while, and when).\nEach nesting level will increase the amount of effort needed to read the code because you need to remember the current \"stack\" (for example, entering conditional statements and loops).\n**Exception:** The nesting levels of the lambda expressions, local classes, and anonymous classes in functions are calculated based on the innermost function. The nesting levels of enclosing methods are not accumulated.\nFunctional decomposition should be implemented to avoid confusion for the developer who reads the code.\nThis will help the reader switch between contexts.\n\n#### <a name=\"r5.1.3\"></a> 5.1.3 Avoid using nested functions\nNested functions create a more complex function context, thereby confusing readers.\nWith nested functions, the visibility context may not be evident to the code reader.\n\n**Invalid example**:\n```kotlin\nfun foo() {\n    fun nested():String {\n        return \"String from nested function\"\n    }\n    println(\"Nested Output: ${nested()}\")\n}\n```\n#### <a name=\"r5.1.4\"></a> 5.1.4 Negated function calls\nDon't use negated function calls if it can be replaced with negated version of this function\n\n**Invalid example**:\n```kotlin\nfun foo() {\n    val list = listOf(1, 2, 3)\n\n    if (!list.isEmpty()) {\n        // Some cool logic\n    }\n}\n```\n\n**Valid example**:\n```kotlin\nfun foo() {\n    val list = listOf(1, 2, 3)\n\n    if (list.isNotEmpty()) {\n        // Some cool logic\n    }\n}\n```\n\n<!-- =============================================================================== -->\n### <a name=\"c5.2\"></a> 5.2 Function arguments\nThe rules for using function arguments are described in the below topics.\n#### <a name=\"r5.2.1\"></a> 5.2.1 The lambda parameter of the function should be placed at the end of the argument list\n\nWith such notation, it is easier to use curly brackets, leading to better code readability.\n\n**Valid example**:\n```kotlin\n// declaration\nfun myFoo(someArg: Int, myLambda: () -> Unit) {\n// ...\n}\n\n// usage\nmyFoo(1) {\nprintln(\"hey\")\n}\n```\n\n#### <a name=\"r5.2.2\"></a> 5.2.2 Number of function parameters should be limited to five\n\nA long argument list is a [code smell](https://en.wikipedia.org/wiki/Code_smell) that leads to less reliable code.\nIt is recommended to reduce the number of parameters. Having **more than five** parameters leads to difficulties in maintenance and conflicts merging.\nIf parameter groups appear in different functions multiple times, these parameters are closely related and can be encapsulated into a single Data Class.\nIt is recommended that you use Data Classes and Maps to unify these function arguments.\n\n#### <a name=\"r5.2.3\"></a> 5.2.3 Use default values for function arguments instead of overloading them\nIn Java, default values for function arguments are prohibited. That is why the function should be overloaded when you need to create a function with fewer arguments.\nIn Kotlin, you can use default arguments instead. This is useful if methods have same modifiers (private/inline/etc.).\nIf you would like to have some different logic and code in these methods - then name them differently accordingly.\n\n**Invalid example**:\n```kotlin\nprivate fun foo(arg: Int) {\n    // ...\n}\n\nprivate fun foo() {\n    // ...\n}\n```\n\n**Valid example**:\n```kotlin\n private fun foo(arg: Int = 0) {\n     // ...\n }\n```\n#### <a name=\"r5.2.4\"></a> 5.2.4 Synchronizing code inside asynchronous code\nTry to avoid using `runBlocking` in asynchronous code\n\n**Invalid example**:\n```kotlin\nGlobalScope.async {\n    runBlocking {\n        count++\n    }\n}\n```\n#### <a name=\"r5.2.5\"></a> 5.2.5 Long lambdas should have explicit parameters\nThe lambda without parameters shouldn't be too long.\nIf a lambda is too long, it can confuse the user. Lambda without parameters should consist of 10 lines (non-empty and non-comment) in total.\n\n#### <a name=\"r5.2.6\"></a> 5.2.6 Avoid using unnecessary, custom label\nExpressions with unnecessary, custom labels generally increase complexity and worsen the maintainability of the code.\n\n**Invalid example**:\n```kotlin\nrun lab@ {\n    list.forEach {\n        return@lab\n    }\n}\n```\n\n**Valid example**:\n```kotlin\nlist.forEachIndexed { index, i ->\n    return@forEachIndexed\n}\n\nlab@ for(i: Int in q) {\n    for (j: Int in q) {\n        println(i)\n        break@lab\n    }\n}\n```\n\n#### <a name=\"r5.2.7\"></a> 5.2.7 Outer lambdas should have explicit parameters.\nThe lambda without parameters shouldn't have inner lambdas.\nIf a lambda has an inner lambda, `it` can confuse the user. Lambda without parameters should be latest.\n\n**Invalid example**:\n```kotlin\narrays.map {\n    it.map { element ->\n        element.foo()\n    }\n}\n```\n\n**Valid example**:\n```kotlin\narrays.map { array ->\n    array.map { it.foo() }\n}\n```\n"
  },
  {
    "path": "info/guide/guide-chapter-6.md",
    "content": "# <a name=\"c6\"></a> 6. Classes, interfaces, and extension functions\n<!-- =============================================================================== -->\n### <a name=\"c6.1\"></a> 6.1 Classes\nThis section describes the rules of denoting classes in your code.\n#### <a name=\"r6.1.1\"></a> 6.1.1  Denoting a class with a single constructor\nWhen a class has a single constructor, it should be defined as a primary constructor in the declaration of the class. If the class contains only one explicit constructor, it should be converted to a primary constructor.\n\n**Invalid example**:\n```kotlin\nclass Test {\n    var a: Int\n    constructor(a: Int) {\n        this.a = a\n    }\n}\n```\n\n**Valid example**:\n```kotlin\nclass Test(var a: Int) { \n    // ...\n}\n\n// in case of any annotations or modifiers used on a constructor:\nclass Test private constructor(var a: Int) { \n    // ...\n}\n```\n\n#### <a name=\"r6.1.2\"></a> 6.1.2 Prefer data classes instead of classes without any functional logic\nSome people say that the data class is a code smell. However, if you need to use it (which makes your code more simple), you can utilize the Kotlin `data class`. The main purpose of this class is to hold data,\nbut also `data class` will automatically generate several useful methods:\n- equals()/hashCode() pair;\n- toString()\n- componentN() functions corresponding to the properties in their order of declaration;\n- copy() function\n\nTherefore, instead of using `normal` classes:\n\n```kotlin\nclass Test {\n    var a: Int = 0\n        get() = field\n        set(value: Int) { field = value}\n}\n\nclass Test {\n    var a: Int = 0\n    var b: Int = 0\n    \n    constructor(a:Int, b: Int) {\n        this.a = a\n        this.b = b\n    }\n}\n\n// or\nclass Test(var a: Int = 0, var b: Int = 0)\n \n// or\nclass Test() {\n    var a: Int = 0\n    var b: Int = 0\n}\n```\n\n**prefer data classes:**\n```kotlin\ndata class Test1(var a: Int = 0, var b: Int = 0)\n```\n\n**Exception 1**: Note that data classes cannot be abstract, open, sealed, or inner; that is why these types of classes cannot be changed to a data class.\n\n**Exception 2**: No need to convert a class to a data class if this class extends some other class or implements an interface.\n\n#### <a name=\"r6.1.3\"></a> 6.1.3 Do not use the primary constructor if it is empty or useless\nThe primary constructor is a part of the class header; it is placed after the class name and type parameters (optional) but can be omitted if it is not used.\n\n**Invalid example**:\n```kotlin\n// simple case that does not need a primary constructor\nclass Test() {\n    var a: Int = 0\n    var b: Int = 0\n}\n\n// empty primary constructor is not needed here\n// it can be replaced with a primary contructor with one argument or removed\nclass Test() {\n    var a  = \"Property\"\n\n    init {\n        println(\"some init\")\n    }\n\n    constructor(a: String): this() {\n        this.a = a\n    }\n}\n```\n\n**Valid example**:\n```kotlin\n// the good example here is a data class; this example also shows that you should get rid of braces for the primary constructor\nclass Test {\n    var a: Int = 0\n    var b: Int = 0\n}\n```\n\n#### <a name=\"r6.1.4\"></a> 6.1.4 Do not use redundant init blocks in your class\nSeveral init blocks are redundant and generally should not be used in your class. The primary constructor cannot contain any code. That is why Kotlin has introduced `init` blocks.\nThese blocks store the code to be run during the class initialization.\nKotlin allows writing multiple initialization blocks executed in the same order as they appear in the class body.\nEven when you follow (rule 3.2)[#r3.2], this makes your code less readable as the programmer needs to keep in mind all init blocks and trace the execution of the code.\nTherefore, you should try to use a single `init` block to reduce the code's complexity. If you need to do some logging or make some calculations before the class property assignment, you can use powerful functional programming. This will reduce the possibility of the error if your `init` blocks' order is accidentally changed and\nmake the code logic more coupled. It is always enough to use one `init` block to implement your idea in Kotlin.\n\n**Invalid example**:\n```kotlin\nclass YourClass(var name: String) {    \n    init {\n        println(\"First initializer block that prints ${name}\")\n    }\n    \n    val property = \"Property: ${name.length}\".also(::println)\n    \n    init {\n        println(\"Second initializer block that prints ${name.length}\")\n    }\n}\n```\n\n**Valid example**:\n```kotlin\nclass YourClass(var name: String) {\n    init {\n        println(\"First initializer block that prints ${name}\")\n    }\n\n    val property = \"Property: ${name.length}\".also { prop ->\n        println(prop)\n        println(\"Second initializer block that prints ${name.length}\")\n    }\n}\n```\n\nThe `init` block was not added to Kotlin to help you initialize your properties; it is needed for more complex tasks. \nTherefore if the `init` block contains only assignments of variables - move it directly to properties to be correctly initialized near the declaration.\nIn some cases, this rule can be in clash with [6.1.1](#r6.1.1), but that should not stop you.\n\n**Invalid example**:\n```kotlin\nclass A(baseUrl: String) {\n    private val customUrl: String\n    init {\n        customUrl = \"$baseUrl/myUrl\"\n    }\n}\n```\n\n**Valid example**:\n```kotlin\nclass A(baseUrl: String) {\n    private val customUrl = \"$baseUrl/myUrl\"\n}\n```\n\n#### <a name=\"r6.1.5\"></a> 6.1.5 Explicit supertype qualification\nThe explicit supertype qualification should not be used if there is no clash between called methods. This rule is applicable to both interfaces and classes.\n\n**Invalid example**:\n```kotlin\nopen class Rectangle {\n    open fun draw() { /* ... */ }\n}\n\nclass Square() : Rectangle() {\n    override fun draw() {\n        super<Rectangle>.draw() // no need in super<Rectangle> here\n    }\n}\n```\n\n#### <a name=\"r6.1.6\"></a> 6.1.6 Abstract class should have at least one abstract method\nAbstract classes are used to force a developer to implement some of its parts in their inheritors.\nWhen the abstract class has no abstract methods, it was set `abstract` incorrectly and can be converted to open class.\n\n**Invalid example**:\n```kotlin\nabstract class NotAbstract {\n    fun foo() {}\n    \n    fun test() {}\n}\n```\n\n**Valid example**:\n```kotlin\nabstract class NotAbstract {\n    abstract fun foo()\n    \n    fun test() {}\n}\n\n// OR\nopen class NotAbstract {\n    fun foo() {}\n    \n    fun test() {}\n}\n\n// OR\nclass NotAbstract {\n    fun foo() {}\n\n    fun test() {}\n}\n```\n\n\n#### <a name=\"r6.1.7\"></a> 6.1.7 When using the \"implicit backing property\" scheme, the name of real and back property should be the same\nKotlin has a mechanism of [backing properties](https://kotlinlang.org/docs/reference/properties.html#backing-properties).\nIn some cases, implicit backing is not enough and it should be done explicitly:\n```kotlin\nprivate var _table: Map<String, Int>? = null\nval table: Map<String, Int>\n    get() {\n        if (_table == null) {\n            _table = HashMap() // Type parameters are inferred\n        }\n        return _table ?: throw AssertionError(\"Set to null by another thread\")\n    }\n```\n\nIn this case, the name of the backing property (`_table`) should be the same as the name of the real property (`table`) but should have an underscore (`_`) prefix.\nIt is one of the exceptions from the [identifier names rule](#r1.2)\n\n#### <a name=\"r6.1.8\"></a> 6.1.8 Avoid using custom getters and setters\nKotlin has a perfect mechanism of [properties](https://kotlinlang.org/docs/reference/properties.html#properties-and-fields).\nKotlin compiler automatically generates `get` and `set` methods for properties and can override them.\n\n**Invalid example:**\n```kotlin \nclass A {\n    var size: Int = 0\n        set(value) {\n            println(\"Side effect\")\n            field = value\n        }\n        // user of this class does not expect calling A.size receive size * 2 \n        get() = field * 2\n}\n```\n\nFrom the callee code, these methods look like access to this property: `A().isEmpty = true` for setter and `A().isEmpty` for getter.\n\nHowever, when `get` and `set` are overridden, it  isn't very clear for a developer who uses this particular class. \nThe developer expects to get the property value but receives some unknown value and some extra side-effect hidden by the custom getter/setter. \nUse extra functions instead to avoid confusion.\n\n\n\n**Valid example**:\n```kotlin \nclass A {\n    var size: Int = 0\n    fun initSize(value: Int) {\n        // some custom logic\n    }\n    \n    // this will not confuse developer and he will get exactly what he expects    \n    fun goodNameThatDescribesThisGetter() = this.size * 2\n}\n```\n\n**Exception:** `Private setters` are only exceptions that are not prohibited by this rule.\n\n#### <a name=\"r6.1.9\"></a> 6.1.9 Never use the name of a variable in the custom getter or setter (possible_bug)\nIf you ignored [recommendation 6.1.8](#r6.1.8), be careful with using the name of the property in your custom getter/setter\nas it can accidentally cause a recursive call and a `StackOverflow Error`. Use the `field` keyword instead.\n\n**Invalid example (very bad)**:\n```kotlin\nvar isEmpty: Boolean\n    set(value) {\n        println(\"Side effect\")\n        isEmpty = value\n    }\n    get() = isEmpty\n```\n\n#### <a name=\"r6.1.10\"></a> 6.1.10 No trivial getters and setters are allowed in the code\nIn Java, trivial getters - are the getters that are just returning the field value.\nTrivial setters - are merely setting the field with a value without any transformation.\nHowever, in Kotlin, trivial getters/setters are generated by default. There is no need to use it explicitly for all types of data structures in Kotlin.\n\n**Invalid example**:\n```kotlin\nclass A {\n    var a: Int = 0 \n    get() = field\n    set(value: Int) { field = value }\n\n    //\n}\n```\n\n**Valid example**:\n```kotlin\nclass A {\n    var a: Int = 0 \n    get() = field\n    set(value: Int) { field = value }\n\n    //\n}\n```\n\n#### <a name=\"r6.1.11\"></a> 6.1.11 Use 'apply' for grouping object initialization\nIn Java, before functional programming became popular, many classes from common libraries used the configuration paradigm.\nTo use these classes, you had to create an object with the constructor with 0-2 arguments and set the fields needed to run the object.\nIn Kotlin, to reduce the number of dummy code line and to group objects [`apply` extension](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/apply.html) was added:  \n \n**Invalid example**:\n```kotlin\nclass HttpClient(var name: String) {\n    var url: String = \"\"\n    var port: String = \"\"\n    var timeout = 0\n    \n    fun doRequest() {}\n}\n\nfun main() {\n    val httpClient = HttpClient(\"myConnection\")\n    httpClient.url = \"http://example.com\"\n    httpClient.port = \"8080\"\n    httpClient.timeout = 100\n    \n    httpCLient.doRequest()\n}   \n\n```\n\n**Valid example**:\n```kotlin\nclass HttpClient(var name: String) {\n    var url: String = \"\"\n    var port: String = \"\"\n    var timeout = 0\n\n    fun doRequest() {}\n}\n\nfun main() {\n    val httpClient = HttpClient(\"myConnection\")\n            .apply {\n                url = \"http://example.com\"\n                port = \"8080\"\n                timeout = 100\n            }\n    httpClient.doRequest()\n}\n```\n\n### <a name=\"r6.1.12\"></a> 6.1.12 Prefer Inline classes when a class has a single property\nIf a class has only one immutable property, then it can be converted to the inline class.\n\nSometimes it is necessary for business logic to create a wrapper around some type. However, it introduces runtime overhead due to additional heap allocations. Moreover, if the wrapped type is primitive, the performance hit is terrible, because primitive types are usually heavily optimized by the runtime, while their wrappers don't get any special treatment.\n\n**Invalid example**:\n```kotlin\nclass Password {\n    val value: String\n}\n```\n\n**Valid example**:\n```kotlin\ninline class Password(val value: String)\n```\n\n<!-- =============================================================================== -->\n### <a name=\"c6.2\"></a>6.2 Extension functions\nThis section describes the rules of using extension functions in your code.\n\n[Extension functions](https://kotlinlang.org/docs/reference/extensions.html) is a killer-feature in Kotlin. \nIt gives you a chance to extend classes that were already implemented in external libraries and helps you to make classes less heavy.\nExtension functions are resolved statically.\n\n#### <a name=\"r6.2.1\"></a> 6.2.1 Use extension functions for making logic of classes less coupled\nIt is recommended that for classes, the non-tightly coupled functions, which are rarely used in the class, should be implemented as extension functions where possible.\nThey should be implemented in the same class/file where they are used. This is a non-deterministic rule, so the code cannot be checked or fixed automatically by a static analyzer.\n\n#### <a name=\"r6.2.2\"></a> 6.2.2 No extension functions with the same name and signature if they extend base and inheritor classes (possible_bug)\nYou should avoid declaring extension functions with the same name and signature if their receivers are base and inheritor classes (possible_bug),\nas extension functions are resolved statically. There could be a situation when a developer implements two extension functions: one is for the base class and\nanother for the inheritor. This can lead to an issue when an incorrect method is used.\n\n**Invalid example**:\n```kotlin\nopen class A\nclass B: A()\n\n// two extension functions with the same signature\nfun A.foo() = \"A\"\nfun B.foo() = \"B\"\n\nfun printClassName(s: A) { println(s.foo()) }\n\n// this call will run foo() method from the base class A, but\n// programmer can expect to run foo() from the class inheritor B\nfun main() { printClassName(B()) }\n```\n\n#### <a name=\"r6.2.3\"></a> 6.2.3 Don't use extension functions for the class in the same file\nYou should not use extension functions for the class in the same file, where it is defined.\n\n**Invalid example**:\n```kotlin\nclass SomeClass {\n    \n}\n\nfun SomeClass.deleteAllSpaces() {\n    \n}\n```\n\n#### <a name=\"r6.2.4\"></a> 6.2.4 You should not use property length with operation - 1, you can change this to lastIndex\nYou should not use property length with operation - 1, you can change this to lastIndex\n\n**Invalid example**:\n```kotlin\nval A = \"name\"\nval B = A.length - 1\nval C = A[A.length - 1]\n```\n\n**Valid example**:\n```kotlin\nval A = \"name\"\nval B = A.lastIndex\nval C = A[A.lastIndex]\n```\n\n\n<!-- =============================================================================== -->\n### <a name=\"c6.3\"></a> 6.3 Interfaces\nAn `Interface` in Kotlin can contain declarations of abstract methods, as well as method implementations. What makes them different from abstract classes is that interfaces cannot store state.\nThey can have properties, but these need to be abstract or to provide accessor implementations.\n\nKotlin's interfaces can define attributes and functions.\nIn Kotlin and Java, the interface is the main presentation means of application programming interface (API) design and should take precedence over the use of (abstract) classes.\n\n<!-- =============================================================================== -->\n### <a name=\"c6.4\"></a> 6.4 Objects\nThis section describes the rules of using objects in code.\n#### <a name=\"r6.4.1\"></a> 6.4.1 Instead of using utility classes/objects, use extensions\nAvoid using utility classes/objects; use extensions instead. As described in [6.2 Extension functions](#c6.2), using extension functions is a powerful method.\nThis enables you to avoid unnecessary complexity and class/object wrapping and use top-level functions instead.\n\n**Invalid example**:\n```kotlin \nobject StringUtil {\n    fun stringInfo(myString: String): Int {\n        return myString.count{ \"something\".contains(it) }\n    }\n}\nStringUtil.stringInfo(\"myStr\")\n```\n\n**Valid example**:\n```kotlin\nfun String.stringInfo(): Int {\n    return this.count{ \"something\".contains(it) }\n}\n\n\"myStr\".stringInfo()\n```\n\n#### <a name=\"r6.4.2\"></a> 6.4.2 Objects should be used for Stateless Interfaces\nKotlin’s objects are extremely useful when you need to implement some interface from an external library that does not have any state.\nThere is no need to use classes for such structures.\n\n**Valid example**:\n```\ninterface I {\n    fun foo()\n}\n\nobject O: I {\n    override fun foo() {}\n}\n```\n### <a name=\"c6.5\"></a> 6.5 Kts Files\nThis section describes general rules for `.kts` files\n#### <a name=\"r6.5.1\"></a> 6.5.1 kts files should wrap logic into top-level scope\nIt is still recommended wrapping logic inside functions and avoid using top-level statements for function calls or wrapping blocks of code\nin top-level scope functions like `run`.\n\n**Valid example**:\n```\nrun {\n    // some code\n}\n\nfun foo() {\n\n}\n```\n"
  },
  {
    "path": "info/guide/table-of-content.md",
    "content": "<img src=\"/logo.svg\" width=\"64px\"/>\n\n# Diktat Coding Convention\n\n### Content\n\n| Chapter             | Content                                                      |\n| ------------------- | ------------------------------------------------------------ |\n| [0. Preface](#c0.1) | [Purpose](#c0.1), [General principles](#c0.2), [Terminology](#c0.3), [Exceptions](#c0.4) |\n| [1. Naming](#c1)    | [Identifiers](#c1.1), [Package names](#c1.2), [Classes, enumeration and interfaces](#c1.3), [Functions](#c1.4), [Constants](#c1.5), [Variables](#c1.6) |\n| [2. Docs](#c2)  | [Kdoc](#c2.1), [File header](#c2.2), [Comments on function header ](#c2.3), [Code comments](#c2.4) |\n| [3. General formatting](#c3)   | [File-related rules](#c3.1), [Braces](#c3.2), [Indentation](#c3.3), [Empty blocks](#c3.4), [Line length](#c3.5), [Line breaks (newlines)](#c3.6), [Blank lines](#c3.7), [Horizontal space](#c3.8), [Enumerations](#c3.9), [Variable declaration](#c3.10), [When expression](#c3.11), [Annotations](#c3.12), [Layout of comments](#c3.13), [Modifiers and constant values](#c3.14), [Strings](#c3.15)|\n| [4. Variables and types](#c4) | [Variables](#c4.1), [Types](#c4.2), [Null safety and variable declarations](#4.3)|\n| [5. Functions](#c5) | [Function design](#c5.1), [Function arguments](#c5.2)|\n| [6. Classes](#c6) | [Classes](#c6.1), [Extension functions](#c6.2), [Interfaces](#c6.3), [Objects](#c6.4) |\n| [7. Kotlin & Java](#c7) |  |\n\n"
  },
  {
    "path": "info/rules-mapping.md",
    "content": "| Diktat Rule | Code Style | Auto-fixed? | Chapter |\n| ----------------------------------------- | ------ | --- | --------- |\n| VARIABLE_NAME_INCORRECT | [1.1.1](guide/diktat-coding-convention.md#r1.1.1) | no | Naming |\n| VARIABLE_HAS_PREFIX | [1.1.1](guide/diktat-coding-convention.md#r1.1.1) | yes | Naming |\n| IDENTIFIER_LENGTH | [1.1.1](guide/diktat-coding-convention.md#r1.1.1) | no | Naming |\n| GENERIC_NAME | [1.1.1](guide/diktat-coding-convention.md#r1.1.1) | yes | Naming |\n| BACKTICKS_PROHIBITED | [1.1.1](guide/diktat-coding-convention.md#r1.1.1) | no | Naming |\n| FILE_NAME_INCORRECT | [1.1.1](guide/diktat-coding-convention.md#r1.1.1) | yes | Naming |\n| EXCEPTION_SUFFIX | [1.1.1](guide/diktat-coding-convention.md#r1.1.1) | yes | Naming |\n| CONFUSING_IDENTIFIER_NAMING | [1.1.1](guide/diktat-coding-convention.md#r1.1.1) | no | Naming |\n| PACKAGE_NAME_MISSING | [1.2.1](guide/diktat-coding-convention.md#r1.2.1) | yes | Naming |\n| PACKAGE_NAME_INCORRECT_CASE | [1.2.1](guide/diktat-coding-convention.md#r1.2.1) | yes | Naming |\n| PACKAGE_NAME_INCORRECT_PREFIX | [1.2.1](guide/diktat-coding-convention.md#r1.2.1) | yes | Naming |\n| PACKAGE_NAME_INCORRECT_SYMBOLS | [1.2.1](guide/diktat-coding-convention.md#r1.2.1) | no | Naming |\n| PACKAGE_NAME_INCORRECT_PATH | [1.2.1](guide/diktat-coding-convention.md#r1.2.1) | yes | Naming |\n| INCORRECT_PACKAGE_SEPARATOR | [1.2.1](guide/diktat-coding-convention.md#r1.2.1) | yes | Naming |\n| CLASS_NAME_INCORRECT | [1.3.1](guide/diktat-coding-convention.md#r1.3.1) | yes | Naming |\n| OBJECT_NAME_INCORRECT | [1.3.1](guide/diktat-coding-convention.md#r1.3.1) | yes | Naming |\n| ENUM_VALUE | [1.3.1](guide/diktat-coding-convention.md#r1.3.1) | yes | Naming |\n| TYPEALIAS_NAME_INCORRECT_CASE | [1.3.1](guide/diktat-coding-convention.md#r1.3.1) | yes | Naming |\n| FUNCTION_NAME_INCORRECT_CASE | [1.4.1](guide/diktat-coding-convention.md#r1.4.1) | yes | Naming |\n| CONSTANT_UPPERCASE | [1.5.1](guide/diktat-coding-convention.md#r1.5.1) | yes | Naming |\n| VARIABLE_NAME_INCORRECT_FORMAT | [1.6.1](guide/diktat-coding-convention.md#r1.6.1) | yes | Naming |\n| FUNCTION_BOOLEAN_PREFIX | [1.6.2](guide/diktat-coding-convention.md#r1.6.2) | yes | Naming |\n| MISSING_KDOC_TOP_LEVEL | [2.1.1](guide/diktat-coding-convention.md#r2.1.1) | no | Comments |\n| MISSING_KDOC_CLASS_ELEMENTS | [2.1.1](guide/diktat-coding-convention.md#r2.1.1) | no | Comments |\n| MISSING_KDOC_ON_FUNCTION | [2.1.1](guide/diktat-coding-convention.md#r2.1.1) | yes | Comments |\n| KDOC_NO_CONSTRUCTOR_PROPERTY | [2.1.1](guide/diktat-coding-convention.md#r2.1.1) | yes | Comments |\n| KDOC_NO_CLASS_BODY_PROPERTIES_IN_HEADER | [2.1.1](guide/diktat-coding-convention.md#r2.1.1) | yes | Comments |\n| KDOC_EXTRA_PROPERTY | [2.1.1](guide/diktat-coding-convention.md#r2.1.1) | no | Comments |\n| KDOC_DUPLICATE_PROPERTY | [2.1.1](guide/diktat-coding-convention.md#r2.1.1) | no | Comments |\n| KDOC_NO_CONSTRUCTOR_PROPERTY_WITH_COMMENT | [2.1.1](guide/diktat-coding-convention.md#r2.1.1) | yes | Comments |\n| KDOC_WITHOUT_PARAM_TAG | [2.1.2](guide/diktat-coding-convention.md#r2.1.2) | yes | Comments |\n| KDOC_WITHOUT_RETURN_TAG | [2.1.2](guide/diktat-coding-convention.md#r2.1.2) | yes | Comments |\n| KDOC_WITHOUT_THROWS_TAG | [2.1.2](guide/diktat-coding-convention.md#r2.1.2) | yes | Comments |\n| KDOC_EMPTY_KDOC | [2.1.3](guide/diktat-coding-convention.md#r2.1.3) | no | Comments |\n| KDOC_WRONG_SPACES_AFTER_TAG | [2.1.3](guide/diktat-coding-convention.md#r2.1.3) | yes | Comments |\n| KDOC_WRONG_TAGS_ORDER | [2.1.3](guide/diktat-coding-convention.md#r2.1.3) | yes | Comments |\n| KDOC_NEWLINES_BEFORE_BASIC_TAGS | [2.1.3](guide/diktat-coding-convention.md#r2.1.3) | yes | Comments |\n| KDOC_NO_NEWLINES_BETWEEN_BASIC_TAGS | [2.1.3](guide/diktat-coding-convention.md#r2.1.3) | yes | Comments |\n| KDOC_NO_NEWLINE_AFTER_SPECIAL_TAGS | [2.1.3](guide/diktat-coding-convention.md#r2.1.3) | yes | Comments |\n| KDOC_NO_DEPRECATED_TAG | [2.1.3](guide/diktat-coding-convention.md#r2.1.3) | yes | Comments |\n| KDOC_CONTAINS_DATE_OR_AUTHOR | [2.1.3](guide/diktat-coding-convention.md#r2.1.3) | no | Comments |\n| KDOC_NO_EMPTY_TAGS | [2.2.1](guide/diktat-coding-convention.md#r2.2.1) | no | Comments |\n| HEADER_WRONG_FORMAT | [2.2.1](guide/diktat-coding-convention.md#r2.2.1) | yes | Comments |\n| HEADER_MISSING_OR_WRONG_COPYRIGHT | [2.2.1](guide/diktat-coding-convention.md#r2.2.1) | yes | Comments |\n| WRONG_COPYRIGHT_YEAR | [2.2.1](guide/diktat-coding-convention.md#r2.2.1) | yes | Comments |\n| HEADER_MISSING_IN_NON_SINGLE_CLASS_FILE | [2.2.1](guide/diktat-coding-convention.md#r2.2.1) | no | Comments |\n| HEADER_NOT_BEFORE_PACKAGE | [2.2.1](guide/diktat-coding-convention.md#r2.2.1) | yes | Comments |\n| KDOC_TRIVIAL_KDOC_ON_FUNCTION | [2.3.1](guide/diktat-coding-convention.md#r2.3.1) | no | Comments |\n| WRONG_NEWLINES_AROUND_KDOC | [2.4.1](guide/diktat-coding-convention.md#r2.4.1) | yes | Comments |\n| FIRST_COMMENT_NO_BLANK_LINE | [2.4.1](guide/diktat-coding-convention.md#r2.4.1) | yes | Comments |\n| COMMENT_WHITE_SPACE | [2.4.1](guide/diktat-coding-convention.md#r2.4.1) | yes | Comments |\n| IF_ELSE_COMMENTS | [2.4.1](guide/diktat-coding-convention.md#r2.4.1) | yes | Comments |\n| COMMENTED_OUT_CODE | [2.4.2](guide/diktat-coding-convention.md#r2.4.2) | no | Comments |\n| FILE_IS_TOO_LONG | [3.1.1](guide/diktat-coding-convention.md#r3.1.1) | no | General |\n| FILE_CONTAINS_ONLY_COMMENTS | [3.1.2](guide/diktat-coding-convention.md#r3.1.2) | no | General |\n| FILE_INCORRECT_BLOCKS_ORDER | [3.1.2](guide/diktat-coding-convention.md#r3.1.2) | yes | General |\n| FILE_NO_BLANK_LINE_BETWEEN_BLOCKS | [3.1.2](guide/diktat-coding-convention.md#r3.1.2) | yes | General |\n| FILE_UNORDERED_IMPORTS | [3.1.2](guide/diktat-coding-convention.md#r3.1.2) | yes | General |\n| FILE_WILDCARD_IMPORTS | [3.1.2](guide/diktat-coding-convention.md#r3.1.2) | no | General |\n| UNUSED_IMPORT | [3.1.2](guide/diktat-coding-convention.md#r3.1.2) | yes | General |\n| FILE_NAME_MATCH_CLASS | [3.1.2](guide/diktat-coding-convention.md#r3.1.2) | yes | General |\n| WRONG_ORDER_IN_CLASS_LIKE_STRUCTURES | [3.1.4](guide/diktat-coding-convention.md#r3.1.4) | yes | General |\n| BLANK_LINE_BETWEEN_PROPERTIES | [3.1.4](guide/diktat-coding-convention.md#r3.1.4) | yes | General |\n| WRONG_DECLARATIONS_ORDER | [3.1.4](guide/diktat-coding-convention.md#r3.1.4) | yes | General |\n| TOP_LEVEL_ORDER | [3.1.5](guide/diktat-coding-convention.md#r3.1.5) | yes | General |\n| NO_BRACES_IN_CONDITIONALS_AND_LOOPS | [3.2.1](guide/diktat-coding-convention.md#r3.2.1) | yes | General |\n| BRACES_BLOCK_STRUCTURE_ERROR | [3.2.2](guide/diktat-coding-convention.md#r3.2.2) | yes | General |\n| WRONG_INDENTATION | [3.3.1](guide/diktat-coding-convention.md#r3.3.1) | yes | General |\n| EMPTY_BLOCK_STRUCTURE_ERROR | [3.4.1](guide/diktat-coding-convention.md#r3.4.1) | yes | General |\n| LONG_LINE | [3.5.1](guide/diktat-coding-convention.md#r3.5.1) | yes | General |\n| MORE_THAN_ONE_STATEMENT_PER_LINE | [3.6.1](guide/diktat-coding-convention.md#r3.6.1) | yes | General |\n| REDUNDANT_SEMICOLON | [3.6.2](guide/diktat-coding-convention.md#r3.6.2) | yes | General |\n| WRONG_NEWLINES | [3.6.2](guide/diktat-coding-convention.md#r3.6.2) | yes | General |\n| TRAILING_COMMA | [3.6.2](guide/diktat-coding-convention.md#r3.6.2) | yes | General |\n| COMPLEX_EXPRESSION | [3.6.3](guide/diktat-coding-convention.md#r3.6.3) | no | General |\n| COMPLEX_BOOLEAN_EXPRESSION | [3.6.4](guide/diktat-coding-convention.md#r3.6.4) | yes | General |\n| TOO_MANY_BLANK_LINES | [3.7.1](guide/diktat-coding-convention.md#r3.7.1) | yes | General |\n| WRONG_WHITESPACE | [3.8.1](guide/diktat-coding-convention.md#r3.8.1) | yes | General |\n| TOO_MANY_CONSECUTIVE_SPACES | [3.8.1](guide/diktat-coding-convention.md#r3.8.1) | yes | General |\n| ENUMS_SEPARATED | [3.9.1](guide/diktat-coding-convention.md#r3.9.1) | yes | General |\n| LOCAL_VARIABLE_EARLY_DECLARATION | [3.10.2](guide/diktat-coding-convention.md#r3.10.2) | no | General |\n| WHEN_WITHOUT_ELSE | [3.11.1](guide/diktat-coding-convention.md#r3.11.1) | yes | General |\n| ANNOTATION_NEW_LINE | [3.12.1](guide/diktat-coding-convention.md#r3.12.1) | yes | General |\n| WRONG_MULTIPLE_MODIFIERS_ORDER | [3.14.1](guide/diktat-coding-convention.md#r3.14.1) | yes | General |\n| LONG_NUMERICAL_VALUES_SEPARATED | [3.14.2](guide/diktat-coding-convention.md#r3.14.2) | yes | General |\n| MAGIC_NUMBER | [3.14.3](guide/diktat-coding-convention.md#r3.14.3) | no | General |\n| STRING_CONCATENATION | [3.15.1](guide/diktat-coding-convention.md#r3.15.1) | yes | General |\n| STRING_TEMPLATE_CURLY_BRACES | [3.15.2](guide/diktat-coding-convention.md#r3.15.2) | yes | General |\n| STRING_TEMPLATE_QUOTES | [3.15.2](guide/diktat-coding-convention.md#r3.15.2) | yes | General |\n| COLLAPSE_IF_STATEMENTS | [3.16.1](guide/diktat-coding-convention.md#r3.16.1) | yes | General |\n| CONVENTIONAL_RANGE | [3.17.1](guide/diktat-coding-convention.md#r3.17.1) | yes | General |\n| DEBUG_PRINT | [3.18.1](guide/diktat-coding-convention.md#r3.18.1) | no | General |\n| FLOAT_IN_ACCURATE_CALCULATIONS | [4.1.1](guide/diktat-coding-convention.md#r4.1.1) | no | Variables |\n| SAY_NO_TO_VAR | [4.1.3](guide/diktat-coding-convention.md#r4.1.3) | no | Variables |\n| SMART_CAST_NEEDED | [4.2.1](guide/diktat-coding-convention.md#r4.2.1) | yes | Variables |\n| TYPE_ALIAS | [4.2.2](guide/diktat-coding-convention.md#r4.2.2) | no | Variables |\n| NULLABLE_PROPERTY_TYPE | [4.3.1](guide/diktat-coding-convention.md#r4.3.1) | yes | Variables |\n| GENERIC_VARIABLE_WRONG_DECLARATION | [4.3.2](guide/diktat-coding-convention.md#r4.3.2) | yes | Variables |\n| AVOID_NULL_CHECKS | [4.3.3](guide/diktat-coding-convention.md#r4.3.3) | yes | Variables |\n| TOO_LONG_FUNCTION | [5.1.1](guide/diktat-coding-convention.md#r5.1.1) | no | Functions |\n| NESTED_BLOCK | [5.1.2](guide/diktat-coding-convention.md#r5.1.2) | no | Functions |\n| AVOID_NESTED_FUNCTIONS | [5.1.3](guide/diktat-coding-convention.md#r5.1.3) | yes | Functions |\n| INVERSE_FUNCTION_PREFERRED | [5.1.4](guide/diktat-coding-convention.md#r5.1.4) | yes | Functions |\n| LAMBDA_IS_NOT_LAST_PARAMETER | [5.2.1](guide/diktat-coding-convention.md#r5.2.1) | no | Functions |\n| TOO_MANY_PARAMETERS | [5.2.2](guide/diktat-coding-convention.md#r5.2.2) | no | Functions |\n| WRONG_OVERLOADING_FUNCTION_ARGUMENTS | [5.2.3](guide/diktat-coding-convention.md#r5.2.3) | no | Functions |\n| RUN_BLOCKING_INSIDE_ASYNC | [5.2.4](guide/diktat-coding-convention.md#r5.2.4) | no | Functions |\n| TOO_MANY_LINES_IN_LAMBDA | [5.2.5](guide/diktat-coding-convention.md#r5.2.5) | no | Functions |\n| CUSTOM_LABEL | [5.2.6](guide/diktat-coding-convention.md#r5.2.6) | no | Functions |\n| PARAMETER_NAME_IN_OUTER_LAMBDA | [5.2.7](guide/diktat-coding-convention.md#r5.2.7) | no | Functions |\n| SINGLE_CONSTRUCTOR_SHOULD_BE_PRIMARY | [6.1.1](guide/diktat-coding-convention.md#r6.1.1) | yes | Classes |\n| USE_DATA_CLASS | [6.1.2](guide/diktat-coding-convention.md#r6.1.2) | no | Classes |\n| EMPTY_PRIMARY_CONSTRUCTOR | [6.1.3](guide/diktat-coding-convention.md#r6.1.3) | yes | Classes |\n| MULTIPLE_INIT_BLOCKS | [6.1.4](guide/diktat-coding-convention.md#r6.1.4) | yes | Classes |\n| USELESS_SUPERTYPE | [6.1.5](guide/diktat-coding-convention.md#r6.1.5) | yes | Classes |\n| CLASS_SHOULD_NOT_BE_ABSTRACT | [6.1.6](guide/diktat-coding-convention.md#r6.1.6) | yes | Classes |\n| NO_CORRESPONDING_PROPERTY | [6.1.7](guide/diktat-coding-convention.md#r6.1.7) | no | Classes |\n| CUSTOM_GETTERS_SETTERS | [6.1.8](guide/diktat-coding-convention.md#r6.1.8) | no | Classes |\n| WRONG_NAME_OF_VARIABLE_INSIDE_ACCESSOR | [6.1.9](guide/diktat-coding-convention.md#r6.1.9) | no | Classes |\n| TRIVIAL_ACCESSORS_ARE_NOT_RECOMMENDED | [6.1.10](guide/diktat-coding-convention.md#r6.1.10) | yes | Classes |\n| COMPACT_OBJECT_INITIALIZATION | [6.1.11](guide/diktat-coding-convention.md#r6.1.11) | yes | Classes |\n| INLINE_CLASS_CAN_BE_USED | [6.1.12](guide/diktat-coding-convention.md#r6.1.12) | yes | Classes |\n| EXTENSION_FUNCTION_SAME_SIGNATURE | [6.2.2](guide/diktat-coding-convention.md#r6.2.2) | no | Classes |\n| EXTENSION_FUNCTION_WITH_CLASS | [6.2.3](guide/diktat-coding-convention.md#r6.2.3) | no | Classes |\n| USE_LAST_INDEX | [6.2.4](guide/diktat-coding-convention.md#r6.2.4) | yes | Classes |\n| AVOID_USING_UTILITY_CLASS | [6.4.1](guide/diktat-coding-convention.md#r6.4.1) | no | Classes |\n| OBJECT_IS_PREFERRED | [6.4.2](guide/diktat-coding-convention.md#r6.4.2) | yes | Classes |\n| RUN_IN_SCRIPT | [6.5.1](guide/diktat-coding-convention.md#r6.5.1) | yes | Classes |\n"
  },
  {
    "path": "renovate.json",
    "content": "{\n  \"enabled\": true,\n  \"dependencyDashboard\": true,\n  \"schedule\": [\n    \"before 4am on Monday\"\n  ],\n  \"packageRules\": [\n    {\n      \"managers\": [\"github-actions\"],\n      \"groupName\": \"all github actions\",\n      \"groupSlug\": \"all-github-actions\"\n    },\n    {\n      \"managers\": [\"gradle\"],\n      \"matchPackagePatterns\": [\n        \"*\"\n      ],\n      \"excludePackagePatterns\": [\n        \"^org\\\\.jetbrains\\\\.kotlin[.:]\",\n        \"^com\\\\.pinterest\\\\.ktlint[.:]\",\n        \"^com\\\\.google\\\\.devtools\\\\.ksp[.:]\"\n      ],\n      \"matchUpdateTypes\": [\n        \"minor\",\n        \"patch\"\n      ],\n      \"groupName\": \"all non-major dependencies (except core Kotlin)\",\n      \"groupSlug\": \"all-minor-patch\"\n    },\n    {\n      \"managers\": [\"gradle\"],\n      \"matchPackagePatterns\": [\n        \"^org\\\\.jetbrains\\\\.kotlin[.:]\",\n        \"^com\\\\.google\\\\.devtools\\\\.ksp[.:]\"\n      ],\n      \"groupName\": \"Kotlin core dependencies\",\n      \"groupSlug\": \"core-kotlin\"\n    },\n    {\n      \"managers\": [\"gradle\"],\n      \"matchPackagePatterns\": [\n        \"^com\\\\.pinterest\\\\.ktlint[.:]\"\n      ],\n      \"groupName\": \"Ktlint\",\n      \"groupSlug\": \"ktlint\"\n    },\n    {\n      \"managers\": [\"gradle\"],\n      \"matchPackageNames\": [\n        \"org.sonatype.plugins:nexus-staging-maven-plugin\"\n      ],\n      \"allowedVersions\": \"<= 1.6.8 || > 1.6.13\"\n    },\n    {\n      \"managers\": [\"gradle\"],\n      \"matchPackageNames\": [\n        \"io.github.microutils:kotlin-logging-jvm\"\n      ],\n      \"allowedVersions\": \"<= 2.1.23\"\n    },\n    {\n      \"managers\": [\"gradle\"],\n      \"matchPackageNames\": [\n        \"org.apache.maven.plugins:maven-plugin-plugin\"\n      ],\n      \"allowedVersions\": \"< 3.7.0\"\n    },\n    {\n      \"managers\": [\"gradle\"],\n      \"matchPackageNames\": [\n        \"org.apache.maven.plugin-tools:maven-plugin-annotations\"\n      ],\n      \"allowedVersions\": \"< 3.7.0\"\n    },\n    {\n      \"managers\": [\"gradle\"],\n      \"matchPackageNames\": [\n        \"commons-cli:commons-cli\"\n      ],\n      \"allowedVersions\": \"!/^20040117\\\\.000000$/\"\n    }\n  ]\n}\n"
  },
  {
    "path": "settings.gradle.kts",
    "content": "rootProject.name = \"diktat\"\n\ndependencyResolutionManagement {\n    repositories {\n        file(\"$rootDir/build/diktat-snapshot\")\n            .takeIf { it.exists() }\n            ?.run {\n                maven {\n                    url = this@run.toURI()\n                }\n            }\n        maven {\n            url = uri(\"https://s01.oss.sonatype.org/content/repositories/snapshots/\")\n            content {\n                includeGroup(\"com.saveourtool.diktat\")\n            }\n        }\n        mavenCentral()\n    }\n}\n\npluginManagement {\n    repositories {\n        file(\"$rootDir/build/diktat-snapshot\")\n            .takeIf { it.exists() }\n            ?.run {\n                maven {\n                    url = this@run.toURI()\n                }\n            }\n        maven {\n            url = uri(\"https://s01.oss.sonatype.org/content/repositories/snapshots/\")\n            content {\n                includeGroup(\"com.saveourtool.diktat\")\n            }\n        }\n        mavenCentral()\n        gradlePluginPortal()\n    }\n}\n\nplugins {\n    id(\"com.gradle.enterprise\") version \"3.16.2\"\n    // starting from Gradle 8, it's needed to configure a repo from which to take Java for a toolchain\n    id(\"org.gradle.toolchains.foojay-resolver-convention\") version \"0.8.0\"\n}\n\nincludeBuild(\"gradle/plugins\")\ninclude(\"diktat-api\")\ninclude(\"diktat-common-test\")\ninclude(\"diktat-ktlint-engine\")\ninclude(\"diktat-gradle-plugin\")\ninclude(\"diktat-maven-plugin\")\ninclude(\"diktat-rules\")\ninclude(\"diktat-ruleset\")\ninclude(\"diktat-dev-ksp\")\ninclude(\"diktat-cli\")\ninclude(\"diktat-runner\")\n\nenableFeaturePreview(\"TYPESAFE_PROJECT_ACCESSORS\")\n\ngradleEnterprise {\n    @Suppress(\"AVOID_NULL_CHECKS\")\n    if (System.getenv(\"CI\") != null) {\n        buildScan {\n            publishAlways()\n            termsOfServiceUrl = \"https://gradle.com/terms-of-service\"\n            termsOfServiceAgree = \"yes\"\n        }\n    }\n}\n"
  },
  {
    "path": "wp/README.md",
    "content": "## White paper\nTo generate a pdf document, you need to go to the `wp` folder and execute\n```\nmake   \n```\n\n**Note**\n\nMinimum `MiKTeX` version - `20.11`"
  },
  {
    "path": "wp/makefile",
    "content": "all:\n\tpdflatex -interaction=nonstopmode wp.tex\n"
  },
  {
    "path": "wp/references.bib",
    "content": "\n%% This BibTeX bibliography file was created using BibDesk.\n%% http://bibdesk.sourceforge.net/\n\n\n%% Saved with string encoding Unicode (UTF-8)\n\n@article{ref:kremenek,\n    Author = {Kremenek, Ted},\n    url = \"https://llvm.org/devmtg/2008-08/Kremenek_StaticAnalyzer.pdf\",\n    Title = {Finding Software Bugs With the Clang Static Analyzer},\n    Year = {2008}}\n    \n@article{ref:spa,\n    Author = {Yegor Bugaenko},\n    Title = {New Object Calculus to Improve Static Program Analysis},\n    Year = {September 30, 2020}\n}\n\n@article{ref:effective,\n    Author = {Wu Jingyue},\n    Title = {Effective Dynamic Detection of Alias Analysis Errors},\n    Year = {2013},\n    pages = \"279-289\",\n    journal = \"Proceedings of the 9th Joint Meeting on Foundations of Software, Engineering\"\n}\n\n@article{ref:simple,\n    Author = {Wand Mitchell},\n    Title = {A Simple Algorithm and Proof for Type Inference},\n    Year = {1987},\n    journal = \"Fundamenta Informaticae 10.2\",\n    pages = \"115–121\"\n}\n\n@article{ref:dis,\n    Author = {Jiri Slaby},\n    Title = {Automatic Bug-finding Techniques for Large Software Projects},\n    Year = {2013}\n}\n\n@book{ref:ast,\ntitle={Abstract Syntax Tree},\nauthor={Miller, F.P. and Vandome, A.F. and John, M.B.},\nisbn={9786133773127},\nurl={https://books.google.ru/books?id=5ns7YgEACAAJ},\nyear={2010},\npublisher={VDM Publishing}\n}\n\n@book{ref:cleancode,\ntitle={Clean Code: A Handbook of Agile Software Craftsmanship},\nauthor={Martin, R.C.},\nisbn={9780132350884},\nlccn={20080240},\nseries={Robert C. Martin series},\nurl={https://books.google.ru/books?id=dwSfGQAACAAJ},\nyear={2009},\npublisher={Prentice Hall}\n}\n\n@book{ref:gang,\ntitle={Design Patterns},\nauthor={Erich Gamma, Richard Helm, Ralph Johnson, John Vlissides},\nisbn={9780201485370},\nyear={2000},\npublisher={Pearson Education}\n}\n\n@book{ref:sca,\n  title={Static Code Analysis: Lint, Static Code Analysis, Data-Flow Analysis, Parasoft, Clang, List of Tools for Static Code Analysis},\n  author={LLC Books},\n  isbn={9781155282619},\n  url={https://books.google.ru/books?id=rYurSQAACAAJ},\n  year={2010},\n  publisher={General Books LLC}\n}\n\n@book{ref:kotlinInAction,\ntitle={Kotlin in Action},\nauthor={Dmitry Jemerov, Svetlana Isakova},\npages = {88-91},\nyear={2017},\npublisher={ Manning Publications}\n}\n\n@article{ref:offKotlin,\n    Author = {Jetbrains},\n    Title = {Kotlin official documentation},\n    url = \"https://kotlinlang.org/docs/reference/\",\n    year = {2020}\n}\n\n@article{ref:cicd,\n    Author = {Sten Pittet},\n    Title = {Continuous integration vs. continuous delivery vs. continuous deployment},\n    url = \"https://www.atlassian.com/continuous-delivery/principles/continuous-integration-vs-delivery-vs-deployment\",\n    year = {2017}\n}\n"
  },
  {
    "path": "wp/sections/appendix.tex",
    "content": "\\subsection{Class diagram}\n\\includegraphics[scale=0.5]{pictures/class.PNG}\n\\subsection{Data Flow diagram}\n\\includegraphics[scale=0.6]{pictures/data_flow.PNG}\n\\subsection{Sequence diagram}\n\\includegraphics[scale=0.7]{pictures/sequence.PNG}\n\\subsection{Use-case diagram}\n\\includegraphics[scale=0.8]{pictures/useCase.png}\n\\subsection{Package diagram}\n\\includegraphics[scale=0.65]{pictures/package.png}\n\\section*{Available Rules}\n\\scriptsize\n\\begin{longtable}{ |l|p{0.8cm}|p{0.8cm}| p{3cm} | }\n\\hline\n\\multicolumn{4}{|c|}{Available Rules} \\\\\n\\hline\n\\textbf{diKTat rule} & \\textbf{code style} & \\textbf{autofix} &  \\textbf{config} \\\\\n\\hline\nVARIABLE\\underline{ }NAME\\underline{ }INCORRECT & \\hyperref[sec:1.1.1]{1.1.1} &  no  &   no  \\\\\nVARIABLE\\underline{ }HAS\\underline{ }PREFIX & \\hyperref[sec:1.1.1]{1.1.1} &  yes  &   no  \\\\\nIDENTIFIER\\underline{ }LENGTH & \\hyperref[sec:1.1.1]{1.1.1} &  no  &   no  \\\\\nGENERIC\\underline{ }NAME & \\hyperref[sec:1.1.1]{1.1.1} &  yes  &   no  \\\\\nBACKTICKS\\underline{ }PROHIBITED & \\hyperref[sec:1.1.1]{1.1.1} &  no  &   no  \\\\\nFILE\\underline{ }NAME\\underline{ }INCORRECT & \\hyperref[sec:1.1.1]{1.1.1} &  yes  &   no  \\\\\nEXCEPTION\\underline{ }SUFFIX & \\hyperref[sec:1.1.1]{1.1.1} &  yes  &   no  \\\\\nCONFUSING\\underline{ }IDENTIFIER\\underline{ }NAMING & \\hyperref[sec:1.1.1]{1.1.1} &  no  &   no  \\\\\nPACKAGE\\underline{ }NAME\\underline{ }MISSING & \\hyperref[sec:1.2.1]{1.2.1} &  yes  &   no  \\\\\nPACKAGE\\underline{ }NAME\\underline{ }INCORRECT\\underline{ }CASE & \\hyperref[sec:1.2.1]{1.2.1} &  yes  &   no  \\\\\nPACKAGE\\underline{ }NAME\\underline{ }INCORRECT\\underline{ }PREFIX & \\hyperref[sec:1.2.1]{1.2.1} &  yes  &   no  \\\\\nPACKAGE\\underline{ }NAME\\underline{ }INCORRECT\\underline{ }SYMBOLS & \\hyperref[sec:1.2.1]{1.2.1} &  no  &   no  \\\\\nPACKAGE\\underline{ }NAME\\underline{ }INCORRECT\\underline{ }PATH & \\hyperref[sec:1.2.1]{1.2.1} &  yes  &   no  \\\\\nINCORRECT\\underline{ }PACKAGE\\underline{ }SEPARATOR & \\hyperref[sec:1.2.1]{1.2.1} &  yes  &   no  \\\\\nCLASS\\underline{ }NAME\\underline{ }INCORRECT & \\hyperref[sec:1.3.1]{1.3.1} &  yes  &   no  \\\\\nOBJECT\\underline{ }NAME\\underline{ }INCORRECT & \\hyperref[sec:1.3.1]{1.3.1} &  yes  &   no  \\\\\nENUM\\underline{ }VALUE & \\hyperref[sec:1.3.1]{1.3.1} &  yes  &   enumStyle: snakeCase, pascalCase  \\\\\nTYPEALIAS\\underline{ }NAME\\underline{ }INCORRECT\\underline{ }CASE & \\hyperref[sec:1.3.1]{1.3.1} &  yes  &   no  \\\\\nFUNCTION\\underline{ }NAME\\underline{ }INCORRECT\\underline{ }CASE & \\hyperref[sec:1.4.1]{1.4.1} &  yes  &   no  \\\\\nCONSTANT\\underline{ }UPPERCASE & \\hyperref[sec:1.5.1]{1.5.1} &  yes  &   no  \\\\\nVARIABLE\\underline{ }NAME\\underline{ }INCORRECT\\underline{ }FORMAT & \\hyperref[sec:1.6.1]{1.6.1} &  yes  &   no  \\\\\nFUNCTION\\underline{ }BOOLEAN\\underline{ }PREFIX & \\hyperref[sec:1.6.2]{1.6.2} &  yes  &   no  \\\\\nMISSING\\underline{ }KDOC\\underline{ }TOP\\underline{ }LEVEL & \\hyperref[sec:2.1.1]{2.1.1} &  no  &   no  \\\\\nMISSING\\underline{ }KDOC\\underline{ }CLASS\\underline{ }ELEMENTS & \\hyperref[sec:2.1.1]{2.1.1} &  no  &   no  \\\\\nMISSING\\underline{ }KDOC\\underline{ }ON\\underline{ }FUNCTION & \\hyperref[sec:2.1.1]{2.1.1} &  yes  &   no  \\\\\nKDOC\\underline{ }NO\\underline{ }CONSTRUCTOR\\underline{ }PROPERTY & \\hyperref[sec:2.1.1]{2.1.1} &  yes  &  no                                                                                                                                                                                                                         \\\\\nKDOC\\underline{ }NO\\underline{ }CLASS\\underline{ }BODY\\underline{ }PROPERTIES\\underline{ }IN\\underline{ }HEADER & \\hyperref[sec:2.1.1]{2.1.1} &  yes  &  no                                                                                                                                                                                                                         \\\\\nKDOC\\underline{ }EXTRA\\underline{ }PROPERTY & \\hyperref[sec:2.1.1]{2.1.1} &  no  &  no   \\\\\nKDOC\\underline{ }NO\\underline{ }CONSTRUCTOR\\underline{ }PROPERTY\\underline{ }WITH\\underline{ }COMMENT & \\hyperref[sec:2.1.1]{2.1.1} &  yes  &  no                                                                                                                                                                                                                         \\\\\nKDOC\\underline{ }WITHOUT\\underline{ }PARAM\\underline{ }TAG & \\hyperref[sec:2.1.2]{2.1.2} &  yes  &   no  \\\\\nKDOC\\underline{ }WITHOUT\\underline{ }RETURN\\underline{ }TAG & \\hyperref[sec:2.1.2]{2.1.2} &  yes  &   no  \\\\\nKDOC\\underline{ }WITHOUT\\underline{ }THROWS\\underline{ }TAG & \\hyperref[sec:2.1.2]{2.1.2} &  yes  &   no  \\\\\nKDOC\\underline{ }EMPTY\\underline{ }KDOC & \\hyperref[sec:2.1.3]{2.1.3} &  no  &   no  \\\\\nKDOC\\underline{ }WRONG\\underline{ }SPACES\\underline{ }AFTER\\underline{ }TAG & \\hyperref[sec:2.1.3]{2.1.3} &  yes  &   no  \\\\\nKDOC\\underline{ }WRONG\\underline{ }TAGS\\underline{ }ORDER & \\hyperref[sec:2.1.3]{2.1.3} &  yes  &   no  \\\\\nKDOC\\underline{ }NEWLINES\\underline{ }BEFORE\\underline{ }BASIC\\underline{ }TAGS & \\hyperref[sec:2.1.3]{2.1.3} &  yes  &   no  \\\\\nKDOC\\underline{ }NO\\underline{ }NEWLINES\\underline{ }BETWEEN\\underline{ }BASIC\\underline{ }TAGS & \\hyperref[sec:2.1.3]{2.1.3} &  yes  &   no  \\\\\nKDOC\\underline{ }NO\\underline{ }NEWLINE\\underline{ }AFTER\\underline{ }SPECIAL\\underline{ }TAGS & \\hyperref[sec:2.1.3]{2.1.3} &  yes  &   no  \\\\\nKDOC\\underline{ }NO\\underline{ }DEPRECATED\\underline{ }TAG & \\hyperref[sec:2.1.3]{2.1.3} &  yes  &   no  \\\\\nKDOC\\underline{ }CONTAINS\\underline{ }DATE\\underline{ }OR\\underline{ }AUTHOR & \\hyperref[sec:2.1.3]{2.1.3} &  no  &   no  \\\\\nKDOC\\underline{ }NO\\underline{ }EMPTY\\underline{ }TAGS & \\hyperref[sec:2.2.1]{2.2.1} &  no  &   no  \\\\\nHEADER\\underline{ }WRONG\\underline{ }FORMAT & \\hyperref[sec:2.2.1]{2.2.1} &  yes  &   no  \\\\\nHEADER\\underline{ }MISSING\\underline{ }OR\\underline{ }WRONG\\underline{ }COPYRIGHT & \\hyperref[sec:2.2.1]{2.2.1} &  yes  &  isCopyrightMandatory, copyrightText (sets the copyright pattern for your project, you also can use `;@currYear;` key word in your text in aim to indicate current year, instead of explicit specifying) \\\\\nWRONG\\underline{ }COPYRIGHT\\underline{ }YEAR & \\hyperref[sec:2.2.1]{2.2.1} &  yes  &   no  \\\\\nHEADER\\underline{ }MISSING\\underline{ }IN\\underline{ }NON\\underline{ }SINGLE\\underline{ }CLASS\\underline{ }FILE & \\hyperref[sec:2.2.1]{2.2.1} &  no  &   no  \\\\\nHEADER\\underline{ }NOT\\underline{ }BEFORE\\underline{ }PACKAGE & \\hyperref[sec:2.2.1]{2.2.1} &  yes  &   no  \\\\\nKDOC\\underline{ }TRIVIAL\\underline{ }KDOC\\underline{ }ON\\underline{ }FUNCTION & \\hyperref[sec:2.3.1]{2.3.1} &  no  &   no  \\\\\nWRONG\\underline{ }NEWLINES\\underline{ }AROUND\\underline{ }KDOC & \\hyperref[sec:2.4.1]{2.4.1} &  yes  &   no  \\\\\nFIRST\\underline{ }COMMENT\\underline{ }NO\\underline{ }BLANK\\underline{ }LINE & \\hyperref[sec:2.4.1]{2.4.1} &  yes  &   no  \\\\\nCOMMENT\\underline{ }WHITE\\underline{ }SPACE & \\hyperref[sec:2.4.1]{2.4.1} &  yes  &   maxSpaces  \\\\\nIF\\underline{ }ELSE\\underline{ }COMMENTS & \\hyperref[sec:2.4.1]{2.4.1} &  yes  &   no  \\\\\nCOMMENTED\\underline{ }OUT\\underline{ }CODE & \\hyperref[sec:2.4.2]{2.4.2} &  no  &   no  \\\\\nFILE\\underline{ }IS\\underline{ }TOO\\underline{ }LONG & \\hyperref[sec:3.1.1]{3.1.1} &  no  &   maxSize  \\\\\nFILE\\underline{ }CONTAINS\\underline{ }ONLY\\underline{ }COMMENTS & \\hyperref[sec:3.1.2]{3.1.2} &  no  &   no  \\\\\nFILE\\underline{ }INCORRECT\\underline{ }BLOCKS\\underline{ }ORDER & \\hyperref[sec:3.1.2]{3.1.2} &  yes  &   no  \\\\\nFILE\\underline{ }NO\\underline{ }BLANK\\underline{ }LINE\\underline{ }BETWEEN\\underline{ }BLOCKS & \\hyperref[sec:3.1.2]{3.1.2} &  yes  &   no  \\\\\nFILE\\underline{ }UNORDERED\\underline{ }IMPORTS & \\hyperref[sec:3.1.2]{3.1.2} &  yes  &   no  \\\\\nFILE\\underline{ }WILDCARD\\underline{ }IMPORTS & \\hyperref[sec:3.1.2]{3.1.2} &  no  &   allowedWildcards           \\\\\nUNUSED\\underline{ }IMPORT & \\hyperref[sec:3.1.2]{3.1.2} &  yes  &   deleteUnusedImport           \\\\\nFILE\\underline{ }NAME\\underline{ }MATCH\\underline{ }CLASS & \\hyperref[sec:3.1.2]{3.1.2} &  yes  &   no  \\\\\nWRONG\\underline{ }ORDER\\underline{ }IN\\underline{ }CLASS\\underline{ }LIKE\\underline{ }STRUCTURES & \\hyperref[sec:3.1.4]{3.1.4} &  yes  &   no  \\\\\nBLANK\\underline{ }LINE\\underline{ }BETWEEN\\underline{ }PROPERTIES & \\hyperref[sec:3.1.4]{3.1.4} &  yes  &   no  \\\\\nWRONG\\underline{ }DECLARATIONS\\underline{ }ORDER & \\hyperref[sec:3.1.4]{3.1.4} &  yes  &   no  \\\\\nTOP\\underline{ }LEVEL\\underline{ }ORDER & \\hyperref[sec:3.1.5]{3.1.5} &  yes  &   no  \\\\\nNO\\underline{ }BRACES\\underline{ }IN\\underline{ }CONDITIONALS\\underline{ }AND\\underline{ }LOOPS & \\hyperref[sec:3.2.1]{3.2.1} &  yes  &   no  \\\\\nBRACES\\underline{ }BLOCK\\underline{ }STRUCTURE\\underline{ }ERROR & \\hyperref[sec:3.2.2]{3.2.2} &  yes  &   openBraceNewline closeBraceNewline  \\\\\nWRONG\\underline{ }INDENTATION & \\hyperref[sec:3.3.1]{3.3.1} &  yes  &  extendedIndentOfParameters alignedParameters extendedIndentForExpressionBodies extendedIndentAfterOperators extendedIndentBeforeDot indentationSize   \\\\\nEMPTY\\underline{ }BLOCK\\underline{ }STRUCTURE\\underline{ }ERROR & \\hyperref[sec:3.4.1]{3.4.1} &  yes  &   allowEmptyBlocks styleEmptyBlockWithNewline  \\\\\nLONG\\underline{ }LINE & \\hyperref[sec:3.5.1]{3.5.1} &  yes  &   lineLength                 \\\\\nMORE\\underline{ }THAN\\underline{ }ONE\\underline{ }STATEMENT\\underline{ }PER\\underline{ }LINE & \\hyperref[sec:3.6.1]{3.6.1} &  yes  &   no  \\\\\nREDUNDANT\\underline{ }SEMICOLON & \\hyperref[sec:3.6.2]{3.6.2} &  yes  &   no  \\\\\nWRONG\\underline{ }NEWLINES & \\hyperref[sec:3.6.2]{3.6.2} &  yes  &   no  \\\\\nTRAILING\\underline{ }COMMA & \\hyperref[sec:3.6.2]{3.6.2} &  yes  &   valueArgument valueParameter indices whenConditions collectionLiteral typeArgument typeParameter destructuringDeclaration  \\\\\nCOMPLEX\\underline{ }EXPRESSION & \\hyperref[sec:3.6.3]{3.6.3} &  no  &   no  \\\\\nCOMPLEX\\underline{ }BOOLEAN\\underline{ }EXPRESSION & \\hyperref[sec:3.6.4]{3.6.4} &  yes  &   no    \\\\\nTOO\\underline{ }MANY\\underline{ }BLANK\\underline{ }LINES & \\hyperref[sec:3.7.1]{3.7.1} &  yes  &   no  \\\\\nWRONG\\underline{ }WHITESPACE & \\hyperref[sec:3.8.1]{3.8.1} &  yes  &   no  \\\\\nTOO\\underline{ }MANY\\underline{ }CONSECUTIVE\\underline{ }SPACES & \\hyperref[sec:3.8.1]{3.8.1} &  yes  &   maxSpaces saveInitialFormattingForEnums  \\\\\nENUMS\\underline{ }SEPARATED & \\hyperref[sec:3.9.1]{3.9.1} &  yes  &   no  \\\\\nLOCAL\\underline{ }VARIABLE\\underline{ }EARLY\\underline{ }DECLARATION & \\hyperref[sec:3.10.2]{3.10.2} &  no  &   no  \\\\\nWHEN\\underline{ }WITHOUT\\underline{ }ELSE & \\hyperref[sec:3.11.1]{3.11.1} &  yes  &   no  \\\\\nANNOTATION\\underline{ }NEW\\underline{ }LINE & \\hyperref[sec:3.12.1]{3.12.1} &  yes  &   no  \\\\\nWRONG\\underline{ }MULTIPLE\\underline{ }MODIFIERS\\underline{ }ORDER & \\hyperref[sec:3.14.1]{3.14.1} &  yes  &   no  \\\\\nLONG\\underline{ }NUMERICAL\\underline{ }VALUES\\underline{ }SEPARATED & \\hyperref[sec:3.14.2]{3.14.2} &  yes  &   maxNumberLength maxBlockLength \\\\\nMAGIC\\underline{ }NUMBER & \\hyperref[sec:3.14.3]{3.14.3} &  no  &  ignoreNumbers, ignoreHashCodeFunction, ignorePropertyDeclaration, ignoreLocalVariableDeclaration, ignoreConstantDeclaration, ignoreCompanionObjectPropertyDeclaration, ignoreEnums, ignoreRanges, ignoreExtensionFunctions \\\\\nSTRING\\underline{ }CONCATENATION & \\hyperref[sec:3.15.1]{3.15.1} &  yes  &   no  \\\\\nSTRING\\underline{ }TEMPLATE\\underline{ }CURLY\\underline{ }BRACES & \\hyperref[sec:3.15.2]{3.15.2} &  yes  &   no  \\\\\nSTRING\\underline{ }TEMPLATE\\underline{ }QUOTES & \\hyperref[sec:3.15.2]{3.15.2} &  yes  &   no  \\\\\nCOLLAPSE\\underline{ }IF\\underline{ }STATEMENTS & \\hyperref[sec:3.16.1]{3.16.1} &  yes  &   no    \\\\\nCONVENTIONAL\\underline{ }RANGE & \\hyperref[sec:3.17.1]{3.17.1} &  yes  &   no    \\\\\nDEBUG\\underline{ }PRINT & \\hyperref[sec:3.18.1]{3.18.1} &  no  &  no \\\\\nFLOAT\\underline{ }IN\\underline{ }ACCURATE\\underline{ }CALCULATIONS & \\hyperref[sec:4.1.1]{4.1.1} &  no  &   no  \\\\\nSAY\\underline{ }NO\\underline{ }TO\\underline{ }VAR & \\hyperref[sec:4.1.3]{4.1.3} &  no  &   no  \\\\\nSMART\\underline{ }CAST\\underline{ }NEEDED & \\hyperref[sec:4.2.1]{4.2.1} &  yes  &   no  \\\\\nTYPE\\underline{ }ALIAS & \\hyperref[sec:4.2.2]{4.2.2} &  no  &   typeReferenceLength        \\\\\nNULLABLE\\underline{ }PROPERTY\\underline{ }TYPE & \\hyperref[sec:4.3.1]{4.3.1} &  yes  &   no  \\\\\nGENERIC\\underline{ }VARIABLE\\underline{ }WRONG\\underline{ }DECLARATION & \\hyperref[sec:4.3.2]{4.3.2} &  yes  &   no  \\\\\nAVOID\\underline{ }NULL\\underline{ }CHECKS & \\hyperref[sec:4.3.3]{4.3.3} &  no  &   no  \\\\\nTOO\\underline{ }LONG\\underline{ }FUNCTION & \\hyperref[sec:5.1.1]{5.1.1} &  no  &  maxFunctionLength isIncludeHeader                                                                                                                                                                                          \\\\\nNESTED\\underline{ }BLOCK & \\hyperref[sec:5.1.2]{5.1.2} &  no  &  maxNestedBlockQuantit                                                                                                                                                                                                      \\\\\nAVOID\\underline{ }NESTED\\underline{ }FUNCTIONS & \\hyperref[sec:5.1.3]{5.1.3} &  yes  &   no  \\\\\nINVERSE\\underline{ }FUNCTION\\underline{ }PREFERRED & \\hyperref[sec:5.1.4]{5.1.4} &  yes  &  - \\\\\nLAMBDA\\underline{ }IS\\underline{ }NOT\\underline{ }LAST\\underline{ }PARAMETER & \\hyperref[sec:5.2.1]{5.2.1} &  no  &  no                                                                                                                                                                                                                         \\\\\nTOO\\underline{ }MANY\\underline{ }PARAMETERS & \\hyperref[sec:5.2.2]{5.2.2} &  no  &  maxParameterListSize                                                                                                                                                                                                       \\\\\nWRONG\\underline{ }OVERLOADING\\underline{ }FUNCTION\\underline{ }ARGUMENTS & \\hyperref[sec:5.2.3]{5.2.3} &  no  &  no                                                                                                                                                                                                                         \\\\\nRUN\\underline{ }BLOCKING\\underline{ }INSIDE\\underline{ }ASYNC & \\hyperref[sec:5.2.4]{5.2.4} &  no  &   no \\\\\nTOO\\underline{ }MANY\\underline{ }LINES\\underline{ }IN\\underline{ }LAMBDA & \\hyperref[sec:5.2.5]{5.2.5} &  no  &  maxLambdaLength                                                                                                                                                                                                            \\\\\nCUSTOM\\underline{ }LABEL & \\hyperref[sec:5.2.6]{5.2.6} &  no  &  no\\\\\nPARAMETER\\underline{ }NAME\\underline{ }IN\\underline{ }OUTER\\underline{ }LAMBDA & \\hyperref[sec:5.2.7]{5.2.7} &  no  &  no\\\\\nSINGLE\\underline{ }CONSTRUCTOR\\underline{ }SHOULD\\underline{ }BE\\underline{ }PRIMARY & \\hyperref[sec:6.1.1]{6.1.1} &  yes  &   no  \\\\\nUSE\\underline{ }DATA\\underline{ }CLASS & \\hyperref[sec:6.1.2]{6.1.2} &  no  &   no  \\\\\nEMPTY\\underline{ }PRIMARY\\underline{ }CONSTRUCTOR & \\hyperref[sec:6.1.3]{6.1.3} &  yes  &   no  \\\\\nMULTIPLE\\underline{ }INIT\\underline{ }BLOCKS & \\hyperref[sec:6.1.4]{6.1.4} &  yes  &   no  \\\\\nUSELESS\\underline{ }SUPERTYPE & \\hyperref[sec:6.1.5]{6.1.5} &  yes  &   no  \\\\\nCLASS\\underline{ }SHOULD\\underline{ }NOT\\underline{ }BE\\underline{ }ABSTRACT & \\hyperref[sec:6.1.6]{6.1.6} &  yes  &   no  \\\\\nNO\\underline{ }CORRESPONDING\\underline{ }PROPERTY & \\hyperref[sec:6.1.7]{6.1.7} &  no  &   no  \\\\\nCUSTOM\\underline{ }GETTERS\\underline{ }SETTERS & \\hyperref[sec:6.1.8]{6.1.8} &  no  &   no  \\\\\nWRONG\\underline{ }NAME\\underline{ }OF\\underline{ }VARIABLE\\underline{ }INSIDE\\underline{ }ACCESSOR & \\hyperref[sec:6.1.9]{6.1.9} &  no  &  no                                                                                                                                                                                                                         \\\\\nTRIVIAL\\underline{ }ACCESSORS\\underline{ }ARE\\underline{ }NOT\\underline{ }RECOMMENDED & \\hyperref[sec:6.1.10]{6.1.10} &  yes  &   no  \\\\\nCOMPACT\\underline{ }OBJECT\\underline{ }INITIALIZATION & \\hyperref[sec:6.1.11]{6.1.11} &  yes  &   no  \\\\\nINLINE\\underline{ }CLASS\\underline{ }CAN\\underline{ }BE\\underline{ }USED & \\hyperref[sec:6.1.12]{6.1.12} &  yes  &  no \\\\\nEXTENSION\\underline{ }FUNCTION\\underline{ }SAME\\underline{ }SIGNATURE & \\hyperref[sec:6.2.2]{6.2.2} &  no  &   no  \\\\\nEXTENSION\\underline{ }FUNCTION\\underline{ }WITH\\underline{ }CLASS & \\hyperref[sec:6.2.3]{6.2.3} &  no  &  no \\\\\nUSE\\underline{ }LAST\\underline{ }INDEX & \\hyperref[sec:6.2.4]{6.2.4} &  yes  &  no                                                                                                                                                                                                                         \\\\\nAVOID\\underline{ }USING\\underline{ }UTILITY\\underline{ }CLASS & \\hyperref[sec:6.4.1]{6.4.1} &  no  &  no \\\\\nOBJECT\\underline{ }IS\\underline{ }PREFERRED & \\hyperref[sec:6.4.2]{6.4.2} &  yes  &  no \\\\\nRUN\\underline{ }IN\\underline{ }SCRIPT & \\hyperref[sec:6.5.1]{6.5.1} &  yes  &  no \\\\\n\\hline\n\\end{longtable}\n%CodeStyle\n\n\\hspace{0.0cm}\\hyperref[sec:]{}\n\\section*{Diktat Coding Style Guide, v.0.0.1}\n\\section*{Table of contents}\n\\hspace{0.0cm}\\hyperref[sec:]{I Preface}\n\\hspace{0.5cm}\\hyperref[sec:]{ I.I Purpose of this document}\n\\hspace{0.5cm}\\hyperref[sec:]{ I.II General principles}\n\\hspace{0.5cm}\\hyperref[sec:]{ I.III Terminology}\n\\hspace{0.5cm}\\hyperref[sec:]{ I.IV Exceptions}\n\\hspace{0.0cm}\\hyperref[sec:1.]{1. Naming}\n\\hspace{0.5cm}\\hyperref[sec:1.1]{ 1.1 Identifiers}\n\\hspace{0.5cm}\\hyperref[sec:1.2]{ 1.2 Packages}\n\\hspace{0.5cm}\\hyperref[sec:1.3]{ 1.3 Classes, enumerations, interfaces}\n\\hspace{0.5cm}\\hyperref[sec:1.4]{ 1.4 Functions}\n\\hspace{0.5cm}\\hyperref[sec:1.5]{ 1.5 Constants}\n\\hspace{0.5cm}\\hyperref[sec:1.6]{ 1.6 Non-constant fields (variables)}\n\\hspace{1.0cm}\\hyperref[sec:1.6.1]{ 1.6.1 Non-constant field name}\n\\hspace{1.0cm}\\hyperref[sec:1.6.2]{ 1.6.2 Boolean variable names with negative meaning}\n\\hspace{0.0cm}\\hyperref[sec:2.]{2. Comments}\n\\hspace{0.5cm}\\hyperref[sec:2.1]{ 2.1 General form of Kdoc}\n\\hspace{1.0cm}\\hyperref[sec:2.1.1]{ 2.1.1 Using KDoc for the public, protected, or internal code elements}\n\\hspace{1.0cm}\\hyperref[sec:2.1.2]{ 2.1.2 Describing methods that have arguments, a return value, or can throw an exception in the KDoc block}\n\\hspace{1.0cm}\\hyperref[sec:2.1.3]{ 2.1.3 Only one space between the Kdoc tag and content. Tags are arranged in the order.}\n\\hspace{0.5cm}\\hyperref[sec:2.2]{ 2.2 Adding comments on the file header}\n\\hspace{0.5cm}\\hyperref[sec:2.3]{ 2.3 Comments on the function header}\n\\hspace{0.5cm}\\hyperref[sec:2.4]{ 2.4 Code comments}\n\\hspace{1.0cm}\\hyperref[sec:2.4.1]{ 2.4.1 Add a blank line between the body of the comment and Kdoc tag-blocks}\n\\hspace{1.0cm}\\hyperref[sec:2.4.2]{ 2.4.2 Do not comment on unused code blocks}\n\\hspace{1.0cm}\\hyperref[sec:2.4.3]{ 2.4.3 Code delivered to the client should not contain TODO/FIXME comments}\n\\hspace{1.0cm}\\hyperref[sec:]{}\n\\hspace{0.0cm}\\hyperref[sec:3.]{3. General formatting (typesetting)}\n\\hspace{0.5cm}\\hyperref[sec:3.1]{ 3.1 File-related rules}\n\\hspace{1.0cm}\\hyperref[sec:3.1.1]{ 3.1.1 Avoid files that are too long}\n\\hspace{1.0cm}\\hyperref[sec:3.1.2]{ 3.1.2 Code blocks in the source file should be separated by one blank line}\n\\hspace{1.0cm}\\hyperref[sec:3.1.3]{ 3.1.3 Import statements order}\n\\hspace{1.0cm}\\hyperref[sec:3.1.4]{ 3.1.4 Order of declaration parts of class-like code structures}\n\\hspace{1.0cm}\\hyperref[sec:3.1.5]{ 3.1.5 Order of declaration of top-level code structures}\n\\hspace{0.5cm}\\hyperref[sec:3.2]{ 3.2 Braces}\n\\hspace{1.0cm}\\hyperref[sec:3.2.1]{ 3.2.1 Using braces in conditional statements and loop blocks}\n\\hspace{1.0cm}\\hyperref[sec:3.2.2]{ 3.2.2 Opening braces are placed at the end of the line in non-empty blocks and block structures}\n\\hspace{0.5cm}\\hyperref[sec:3.3]{ 3.3 Indentation}\n\\hspace{0.5cm}\\hyperref[sec:3.4]{ 3.4 Empty blocks}\n\\hspace{0.5cm}\\hyperref[sec:3.5]{ 3.5 Line length}\n\\hspace{0.5cm}\\hyperref[sec:3.6]{ 3.6 Line breaks (newlines)}\n\\hspace{1.0cm}\\hyperref[sec:3.6.1]{ 3.6.1 Each line can have a maximum of one statement}\n\\hspace{1.0cm}\\hyperref[sec:3.6.2]{ 3.6.2 Rules for line-breaking}\n\\hspace{0.5cm}\\hyperref[sec:3.7]{ 3.7 Using blank lines}\n\\hspace{0.5cm}\\hyperref[sec:3.8]{ 3.8 Horizontal space}\n\\hspace{1.0cm}\\hyperref[sec:3.8.1]{ 3.8.1 Usage of whitespace for code separation}\n\\hspace{1.0cm}\\hyperref[sec:3.8.2]{ 3.8.2 No spaces for horizontal alignment}\n\\hspace{0.5cm}\\hyperref[sec:3.9]{ 3.9 Enumerations}\n\\hspace{0.5cm}\\hyperref[sec:3.10]{ 3.10 Variable declaration}\n\\hspace{1.0cm}\\hyperref[sec:3.10.1]{ 3.10.1 Declare one variable per line}\n\\hspace{1.0cm}\\hyperref[sec:3.10.2]{ 3.10.2 Variables should be declared near the line where they are first used}\n\\hspace{0.5cm}\\hyperref[sec:3.11]{ 3.11 'When' expression}\n\\hspace{0.5cm}\\hyperref[sec:3.12]{ 3.12 Annotations}\n\\hspace{0.5cm}\\hyperref[sec:3.13]{ 3.13 Block comments}\n\\hspace{0.5cm}\\hyperref[sec:3.14]{ 3.14 Modifiers and constant values}\n\\hspace{1.0cm}\\hyperref[sec:3.14.1]{ 3.14.1 Declaration with multiple modifiers}\n\\hspace{1.0cm}\\hyperref[sec:3.14.2]{ 3.14.2 Separate long numerical values with an underscore}\n\\hspace{1.0cm}\\hyperref[sec:3.15]{ 3.15 Strings}\n\\hspace{1.0cm}\\hyperref[sec:3.15.1]{ 3.15.1 Concatenation of Strings}\n\\hspace{1.0cm}\\hyperref[sec:3.15.2]{ 3.15.2 String template format}\n\\hspace{0.0cm}\\hyperref[sec:4.]{4. Variables and types}\n\\hspace{0.5cm}\\hyperref[sec:4.1]{ 4.1 Variables}\n\\hspace{1.0cm}\\hyperref[sec:4.1.1]{ 4.1.1 Do not use Float and Double types when accurate calculations are needed}\n\\hspace{1.0cm}\\hyperref[sec:4.1.2]{ 4.1.2 Comparing numeric float type values}\n\\hspace{1.0cm}\\hyperref[sec:4.1.3]{ 4.1.3 Try to use 'val' instead of 'var' for variable declaration SAY_NO_TO_VAR}\n\\hspace{0.5cm}\\hyperref[sec:4.2]{ 4.2 Types}\n\\hspace{1.0cm}\\hyperref[sec:4.2.1]{ 4.2.1 Use Contracts and smart cast as much as possible}\n\\hspace{1.0cm}\\hyperref[sec:4.2.2]{ 4.2.2 Try to use type alias to represent types making code more readable}\n\\hspace{0.5cm}\\hyperref[sec:4.3]{ 4.3 Null safety and variable declarations}\n\\hspace{1.0cm}\\hyperref[sec:4.3.1]{ 4.3.1 Avoid declaring variables with nullable types, especially from Kotlin stdlib}\n\\hspace{1.0cm}\\hyperref[sec:4.3.2]{ 4.3.2 Variables of generic types should have an explicit type declaration}\n\\hspace{1.0cm}\\hyperref[sec:4.3.3]{ 4.3.3 Null-safety}\n\\hspace{0.0cm}\\hyperref[sec:5.]{5. Functions}\n\\hspace{0.5cm}\\hyperref[sec:5.1]{ 5.1 Function design}\n\\hspace{1.0cm}\\hyperref[sec:5.1.1]{ 5.1.1 Avoid functions that are too long }\n\\hspace{1.0cm}\\hyperref[sec:5.1.2]{ 5.1.2 Avoid deep nesting of function code blocks, limiting to four levels}\n\\hspace{1.0cm}\\hyperref[sec:5.1.3]{ 5.1.3 Avoid using nested functions}\n\\hspace{1.0cm}\\hyperref[sec:5.1.4]{ 5.1.4 Negated function calls}\n\\hspace{0.5cm}\\hyperref[sec:5.2]{ 5.2 Function arguments}\n\\hspace{1.0cm}\\hyperref[sec:5.2.1]{ 5.2.1 The lambda parameter of the function should be placed at the end of the argument list}\n\\hspace{1.0cm}\\hyperref[sec:5.2.2]{ 5.2.2 Number of function parameters should be limited to five}\n\\hspace{1.0cm}\\hyperref[sec:5.2.3]{ 5.2.3 Use default values for function arguments instead of overloading them}\n\\hspace{1.0cm}\\hyperref[sec:5.2.4]{ 5.2.4 Synchronizing code inside asynchronous code}\n\\hspace{1.0cm}\\hyperref[sec:5.2.5]{ 5.2.5 Long lambdas should have explicit parameters}\n\\hspace{1.0cm}\\hyperref[sec:5.2.6]{ 5.2.6 Avoid using unnecessary, custom label}\n\\hspace{0.0cm}\\hyperref[sec:6.]{6. Classes, interfaces, and extension functions}\n\\hspace{0.5cm}\\hyperref[sec:6.1]{ 6.1 Classes}\n\\hspace{1.0cm}\\hyperref[sec:6.1.1]{ 6.1.1 Denoting a class with a single constructor}\n\\hspace{1.0cm}\\hyperref[sec:6.1.2]{ 6.1.2 Prefer data classes instead of classes without any functional logic}\n\\hspace{1.0cm}\\hyperref[sec:6.1.3]{ 6.1.3 Do not use the primary constructor if it is empty or useless}\n\\hspace{1.0cm}\\hyperref[sec:6.1.4]{ 6.1.4 Do not use redundant init blocks in your class}\n\\hspace{1.0cm}\\hyperref[sec:6.1.5]{ 6.1.5 Explicit supertype qualification}\n\\hspace{1.0cm}\\hyperref[sec:6.1.6]{ 6.1.6 Abstract class should have at least one abstract method}\n\\hspace{1.0cm}\\hyperref[sec:6.1.7]{ 6.1.7 When using the \"implicit backing property\" scheme, the name of real and back property should be the same}\n\\hspace{1.0cm}\\hyperref[sec:6.1.8]{ 6.1.8 Avoid using custom getters and setters}\n\\hspace{1.0cm}\\hyperref[sec:6.1.9]{ 6.1.9 Never use the name of a variable in the custom getter or setter (possible_bug)}\n\\hspace{1.0cm}\\hyperref[sec:6.1.10]{ 6.1.10 No trivial getters and setters are allowed in the code}\n\\hspace{1.0cm}\\hyperref[sec:6.1.11]{ 6.1.11 Use 'apply' for grouping object initialization}\n\\hspace{1.0cm}\\hyperref[sec:6.1.12]{ 6.1.12 Prefer Inline classes when a class has a single property}\n\\hspace{0.5cm}\\hyperref[sec:6.2]{ 6.2 Extension functions}\n\\hspace{1.0cm}\\hyperref[sec:6.2.1]{ 6.2.1 Use extension functions for making logic of classes less coupled}\n\\hspace{1.0cm}\\hyperref[sec:6.2.2]{ 6.2.2 No extension functions with the same name and signature if they extend base and inheritor classes (possible_bug)}\n\\hspace{1.0cm}\\hyperref[sec:6.2.3]{ 6.2.3 Don't use extension functions for the class in the same file}\n\\hspace{0.5cm}\\hyperref[sec:6.3]{ 6.3 Interfaces}\n\\hspace{0.5cm}\\hyperref[sec:6.4]{ 6.4 Objects}\n\\hspace{1.0cm}\\hyperref[sec:6.4.1]{ 6.4.1 Instead of using utility classes/objects, use extensions}\n\\hspace{1.0cm}\\hyperref[sec:6.4.2]{ 6.4.2 Objects should be used for Stateless Interfaces}\n\\section*{Diktat Coding Style Guide}\n\\section*{International version, v.0.0.1}\n\\hspace{0.0cm}\\hyperref[sec:]{<img src=\"logo.svg\" width=\"64px\"/>}\n\\subsection*{\\textbf{Purpose of this document}}\n\\label{sec:}\nThe purpose of this document is to provide a specification that software developers could reference to enhance their ability to write consistent, easy-to-read, and high-quality code.\nSuch a specification will ultimately improve software development efficiency and product competitiveness.\nFor the code to be considered high-quality, it must entail the following characteristics:\n1.\tSimplicity\n2.\tMaintainability\n3.\tReliability\n4.\tTestability\n5.\tEfficiency\n6.\tPortability\n7.\tReusability\n\\subsection*{\\textbf{General principles}}\nLike other modern programming languages, Kotlin is an advanced programming language that complies with the following general principles:\n1.\tClarity — a necessary feature of programs that are easy to maintain and refactor.\n2.\tSimplicity — a code is easy to understand and implement.\n3.\tConsistency — enables a code to be easily modified, reviewed, and understood by the team members. Unification is particularly important when the same team works on the same project, utilizing similar styles enabling a code to be easily modified, reviewed, and understood by the team members.\nAlso, we need to consider the following factors when programming on Kotlin:\n1. Writing clean and simple Kotlin code\n    Kotlin combines two of the main programming paradigms: functional and object-oriented.\n    Both of these paradigms are trusted and well-known software engineering practices.\n    As a young programming language, Kotlin is built on top of well-established languages such as Java, C++, C\\#, and Scala.\n    This enables Kotlin to introduce many features that help a developer write cleaner, more readable code while also reducing the number of complex code structures. For example, type and null safety, extension functions, infix syntax, immutability, val/var differentiation, expression-oriented features, \"when\" statements, much easier work with collections, type auto conversion, and other syntactic sugar.\n2. Following Kotlin idioms\n    The author of Kotlin, Andrey Breslav, mentioned that Kotlin is both pragmatic and practical, but not academic.\n    Its pragmatic features enable ideas to be transformed into real working software easily. Kotlin is closer to natural languages than its predecessors, and it implements the following design principles: readability, reusability, interoperability, security, and tool-friendliness (https://blog.jetbrains.com/kotlin/2018/10/kotlinconf-2018-announcements/).\n3. Using Kotlin efficiently\n    Some Kotlin features can help you to write higher-performance code: including rich coroutine library, sequences, inline functions/classes, arrays of basic types, tailRec, and CallsInPlace of contract.\n\\subsection*{\\textbf{Terminology}}\n\\textbf{Rules} — conventions that should be followed when programming.\n\\textbf{Recommendations} — conventions that should be considered when programming.\n\\textbf{Explanation} — necessary explanations of rules and recommendations.\n\\textbf{Valid Example} — recommended examples of rules and recommendations.\n\\textbf{Invalid Example} — not recommended examples of rules and recommendations.\nUnless otherwise stated, this specification applies to versions 1.3 and later of Kotlin.\n\\subsection*{\\textbf{Exceptions}}\nEven though exceptions may exist, it is essential to understand why rules and recommendations are needed.\nDepending on a project situation or personal habits, you can break some of the rules. However, remember that one exception may lead to many and eventually can destroy code consistency. As such, there should be very few exceptions.\nWhen modifying open-source code or third-party code, you can choose to use the code style from this open-source project (instead of using the existing specifications) to maintain consistency.\nSoftware that is directly based on the Android native operating system interface, such as the Android Framework, remains consistent with the Android style.\n\\section*{\\textbf{1. Naming}}\n\\label{sec:1.}\nIn programming, it is not always easy to meaningfully and appropriately name variables, functions, classes, etc. Using meaningful names helps to clearly express your code's main ideas and functionality and avoid misinterpretation, unnecessary coding and decoding, \"magic\" numbers, and inappropriate abbreviations.\nNote: The source file encoding format (including comments) must be UTF-8 only. The ASCII horizontal space character (0x20, that is, space) is the only permitted whitespace character. Tabs should not be used for indentation.\n\\subsection*{\\textbf{1.1 Identifiers}}\n\\label{sec:1.1}\nThis section describes the general rules for naming identifiers.\n\\subsubsection*{\\textbf{1.1.1 Identifiers naming conventions}}\n\\leavevmode\\newline\n\\label{sec:1.1.1}\nFor identifiers, use the following naming conventions:\n1.\tAll identifiers should use only ASCII letters or digits, and the names should match regular expressions \\textbf{\\textbackslash w\\{2,64\\}}.\nExplanation: Each valid identifier name should match the regular expression \\textbf{\\textbackslash w\\{2,64\\}}.\n\\textbf{\\{2,64\\}} means that the name length is 2 to 64 characters, and the length of the variable name should be proportional to its life range, functionality, and responsibility.\nName lengths of less than 31 characters are generally recommended. However, this depends on the project. Otherwise, a class declaration with generics or inheritance from a superclass can cause line breaking.\nNo special prefix or suffix should be used in names. The following examples are inappropriate names: name\\_, mName, s\\_name, and kName.\n2.\tChoose file names that would describe the content. Use camel case (PascalCase) and \\textbf{.kt} extension.\n3.\tTypical examples of naming:\n\\begin{center}\n\\begin{tabular}{ |p{5.0cm}|p{5.0cm}|p{5.0cm}| }\n\\hline\nMeaning&Correct&Incorrect\\\\\n\\hline\n \"XML Http Request\" & XmlHttpRequest & XMLHTTPRequest \\\\\n \"new customer ID\" & newCustomerId & newCustomerID \\\\\n \"inner stopwatch\" & innerStopwatch & innerStopWatch \\\\\n \"supports IPv6 on iOS\" & supportsIpv6OnIos & supportsIPv6OnIOS \\\\\n \"YouTube importer\" & YouTubeImporter & YoutubeImporter \\\\\n\\hline\n\\end{tabular}\n\\end{center}\n4.\tThe usage of (\\textbf{}) and free naming for functions and identifiers are prohibited. For example, the following code is not recommended:\n\\begin{lstlisting}[language=Kotlin]\nval `my dummy name-with-minus` = \"value\"\n\\end{lstlisting}\nThe only exception is function names in \\textbf{Unit tests.}\n5.\tBackticks (\\textbf{}) should not be used for identifiers, except the names of test methods (marked with @Test annotation):\n\\begin{lstlisting}[language=Kotlin]\n @Test fun `my test`() { /*...*/ }\n\\end{lstlisting}\n6.  The following table contains some characters that may cause confusion. Be careful when using them as identifiers. To avoid issues, use other names instead.\n\\begin{center}\n\\begin{tabular}{ |p{5.0cm}|p{5.0cm}|p{5.0cm}| }\n\\hline\nExpected&Confusing name&Suggested name\\\\\n\\hline\n 0 (zero)      & O, D                     & obj, dgt         \\\\\n 1 (one)       & I, l                     & it, ln, line     \\\\\n 2 (two)       & Z                        & n1, n2           \\\\\n 5 (five)      & S                        & xs, str          \\\\\n 6 (six)       & e                        & ex, elm          \\\\\n 8 (eight)     & B                        & bt, nxt          \\\\\n n,h           & h,n                      & nr, head, height \\\\\n rn, m         & m,rn                     & mbr, item        \\\\\n\\hline\n\\end{tabular}\n\\end{center}\n\\textbf{Exceptions:}\n- The i,j,k variables used in loops are part of the industry standard. One symbol can be used for such variables.\n- The \\textbf{e} variable can be used to catch exceptions in catch block: \\textbf{catch (e: Exception) \\{\\}}\n- The Java community generally does not recommend the use of prefixes. However, when developing Android code, you can use the s and m prefixes for static and non-public non-static fields, respectively.\nNote that prefixing can also negatively affect the style and the auto-generation of getters and setters.\n\\begin{center}\n\\begin{tabular}{ |p{7.5cm}|p{7.5cm}| }\n\\hline\nType&Naming style\\\\\n\\hline\n Interfaces, classes, annotations, enumerated types, and object type names & Camel case, starting with a capital letter. Test classes have a Test suffix. The filename is 'TopClassName'.kt.  \\\\\n Class fields, local variables, methods, and method parameters & Camel case starting with a low case letter. Test methods can be underlined with '\\_'; the only exception is [backing properties]\\\\\n Static constants and enumerated values & Only uppercase underlined with '\\_' \\\\\n Generic type variable & Single capital letter, which can be followed by a number, for example: `E, T, U, X, T2` \\\\\n Exceptions & Same as class names, but with a suffix Exception, for example: `AccessException` and `NullPointerException`\\\\\n\\hline\n\\end{tabular}\n\\end{center}\n\\subsection*{\\textbf{1.2 Packages}}\n\\label{sec:1.2}\n\\subsubsection*{\\textbf{Rule 1.2.1 Package names dots}}\n\\leavevmode\\newline\nPackage names are in lower case and separated by dots. Code developed within your company should start with \\textbf{your.company.domain.} Numbers are permitted in package names.\nEach file should have a \\textbf{package} directive.\nPackage names are all written in lowercase, and consecutive words are concatenated together (no underscores). Package names should contain both the product or module names and the department (or team) name to prevent conflicts with other teams.  Numbers are not permitted. For example: \\textbf{org.apache.commons.lang3}, \\textbf{xxx.yyy.v2}.\n\\textbf{Exceptions:}\n- In certain cases, such as open-source projects or commercial cooperation, package names should not start with \\textbf{your.company.domain.}\n- If the package name starts with a number or other character that cannot be used at the beginning of the Java/Kotlin package name, then underscores are allowed. For example: \\textbf{com.example.\\_123name}.\n- Underscores are sometimes permitted if the package name contains reserved Java/Kotlin keywords, such as \\textbf{org.example.hyphenated\\_name}, \\textbf{int\\_.example}.\n\\textbf{Valid example}:\n\\begin{lstlisting}[language=Kotlin]\npackage your.company.domain.mobilecontrol.views\n\\end{lstlisting}\n\\subsection*{\\textbf{1.3 Classes}}\n\\label{sec:1.3}\nThis section describes the general rules for naming classes, enumerations, and interfaces.\n\\subsubsection*{\\textbf{1.3.1 Classes}}\n\\leavevmode\\newline\n\\label{sec:1.3.1}\nClasses, enumerations, and interface names use \\textbf{UpperCamelCase} nomenclature. Follow the naming rules described below:\n1.\tA class name is usually a noun (or a noun phrase) denoted using the camel case nomenclature, such as UpperCamelCase. For example: \\textbf{Character} or \\textbf{ImmutableList}.\nAn interface name can also be a noun or noun phrase (such as \\textbf{List}) or an adjective or adjective phrase (such as \\textbf{Readable}).\nNote that verbs are not used to name classes. However, nouns (such as \\textbf{Customer}, \\textbf{WikiPage}, and \\textbf{Account}) can be used. Try to avoid using vague words such as \\textbf{Manager} and \\textbf{Process}.\n2.\tTest classes start with the name of the class they are testing and end with 'Test'. For example, \\textbf{HashTest} or \\textbf{HashIntegrationTest}.\n\\textbf{Invalid example}:\n\\begin{lstlisting}[language=Kotlin]\nclass marcoPolo {}\nclass XMLService {}\ninterface TAPromotion {}\nclass info {}\n\\end{lstlisting}\n\\textbf{Valid example}:\n\\begin{lstlisting}[language=Kotlin]\nclass MarcoPolo {}\nclass XmlService {}\ninterface TaPromotion {}\nclass Order {}\n\\end{lstlisting}\n\\subsection*{\\textbf{1.4 Functions}}\n\\label{sec:1.4}\nThis section describes the general rules for naming functions.\n\\subsubsection*{\\textbf{1.4.1 Function names should be in camel case}}\n\\leavevmode\\newline\n\\label{sec:1.4.1}\nFunction names should use \\textbf{lowerCamelCase} nomenclature. Follow the naming rules described below:\n1.\tFunction names are usually verbs or verb phrases denoted with the camel case nomenclature (\\textbf{lowerCamelCase}).\nFor example: \\textbf{sendMessage}, \\textbf{stopProcess}, or \\textbf{calculateValue}.\nTo name functions, use the following formatting rules:\na) To get, modify, or calculate a certain value: get + non-boolean field(). Note that the Kotlin compiler automatically generates getters for some classes, applying the special syntax preferred for the 'get' fields: kotlin private val field: String get() \\{ \\}. kotlin private val field: String get() \\{ \\}.\n\\begin{lstlisting}[language=Kotlin]\nprivate val field: String\nget() {\n}\n\\end{lstlisting}\nNote: The calling property access syntax is preferred to call getter directly. In this case, the Kotlin compiler automatically calls the corresponding getter.\nb) \\textbf{is} + boolean variable name()\nc) \\textbf{set} + field/attribute name(). However, note that the syntax and code generation for Kotlin are completely the same as those described for the getters in point a.\nd) \\textbf{has} + Noun / adjective ()\ne) verb()\nNote: Note: Verb are primarily used for the action objects, such as \\textbf{document.print ()}\nf) verb + noun()\ng) The Callback function allows the names that use the preposition + verb format, such as: \\textbf{onCreate()}, \\textbf{onDestroy()}, \\textbf{toString()}.\n\\textbf{Invalid example}:\n\\begin{lstlisting}[language=Kotlin]\nfun type(): String\nfun Finished(): Boolean\nfun visible(boolean)\nfun DRAW()\nfun KeyListener(Listener)\n\\end{lstlisting}\n\\textbf{Valid example}:\n\\begin{lstlisting}[language=Kotlin]\nfun getType(): String\nfun isFinished(): Boolean\nfun setVisible(boolean)\nfun draw()\nfun addKeyListener(Listener)\n\\end{lstlisting}\n2.\tAn underscore (\\textbf{\\_}) can be included in the JUnit test function name and should be used as a separator. Each logical part is denoted in \\textbf{lowerCamelCase}, for example, a typical pattern of using underscore: \\textbf{pop\\_emptyStack}.\n\\subsection*{\\textbf{1.5 Constants}}\n\\label{sec:1.5}\nThis section describes the general rules for naming constraints.\n\\subsubsection*{\\textbf{1.5.1 Using UPPER case and underscore characters in a constraint name}}\n\\leavevmode\\newline\n\\label{sec:1.5.1}\nConstant names should be in UPPER case, words separated by underscore. The general constant naming conventions are listed below:\n1. Constants are attributes created with the \\textbf{const} keyword or top-level/\\textbf{val} local variables of an object that holds immutable data. In most cases, constants can be identified as a \\textbf{const val} property from the \\textbf{object}/\\textbf{companion object}/file top level. These variables contain fixed constant values that typically should never be changed by programmers. This includes basic types, strings, immutable types, and immutable collections of immutable types. The value is not constant for the object, which state can be changed.\n2. Constant names should contain only uppercase letters separated by an underscores. They should have a val or const val modifier to make them final explicitly. In most cases, if you need to specify a constant value, then you need to create it with the \"const val\" modifier. Note that not all \\textbf{val} variables are constants.\n3. Objects with immutable content, such as \\textbf{Logger} and \\textbf{Lock}, can be in uppercase as constants or have camel case as regular variables.\n4. Use meaningful constants instead of \\textbf{magic numbers}. SQL or logging strings should not be treated as magic numbers, nor should they be defined as string constants.\nMagic constants, such as \\textbf{NUM\\_FIVE = 5} or \\textbf{NUM\\_5 = 5} should not be treated as constants. This is because mistakes will easily be made if they are changed to \\textbf{NUM\\_5 = 50} or 55.\nThese constants typically represent business logic values, such as measures, capacity, scope, location, tax rate, promotional discounts, and power base multiples in algorithms.\nYou can avoid using magic numbers with the following method:\n- Using library functions and APIs. For example, instead of checking that \\textbf{size == 0}, use \\textbf{isEmpty()} function. To work with \\textbf{time}, use built-ins from \\textbf{java.time API}.\n- Enumerations can be used to name patterns. Refer to [Recommended usage scenario for enumeration in 3.9].\n\\textbf{Invalid example}:\n\\begin{lstlisting}[language=Kotlin]\nvar int MAXUSERNUM = 200;\nval String sL = \"Launcher\";\n\\end{lstlisting}\n\\textbf{Valid example}:\n\\begin{lstlisting}[language=Kotlin]\nconst val int MAX_USER_NUM = 200;\nconst val String APPLICATION_NAME = \"Launcher\";\n\\end{lstlisting}\n\\subsection*{\\textbf{1.6 Non-constant fields}}\n\\label{sec:1.6}\nThis section describes the general rules for naming variables.\n\\subsubsection*{\\textbf{1.6.1 Non-constant field name}}\n\\leavevmode\\newline\n\\label{sec:1.6.1}\nNon-constant field names should use camel case and start with a lowercase letter.\nA local variable cannot be treated as constant even if it is final and immutable. Therefore, it should not use the preceding rules. Names of collection type variables (sets, lists, etc.) should contain plural nouns.\nFor example: \\textbf{var namesList: List<String>}\nNames of non-constant variables should use \\textbf{lowerCamelCase}. The name of the final immutable field used to store the singleton object can use the same camel case notation.\n\\textbf{Invalid example}:\n\\begin{lstlisting}[language=Kotlin]\ncustomername: String\nuser: List<String> = listof()\n\\end{lstlisting}\n\\textbf{Valid example}:\n\\begin{lstlisting}[language=Kotlin]\nvar customerName: String\nval users: List<String> = listOf();\nval mutableCollection: MutableSet<String> = HashSet()\n\\end{lstlisting}\n\\subsubsection*{\\textbf{1.6.2 Boolean variable names with negative meaning}}\n\\leavevmode\\newline\n\\label{sec:1.6.2}\nAvoid using Boolean variable names with a negative meaning. When using a logical operator and name with a negative meaning, the code may be difficult to understand, which is referred to as the \"double negative\".\nFor instance, it is not easy to understand the meaning of !isNotError.\nThe JavaBeans specification automatically generates isXxx() getters for attributes of Boolean classes.\nHowever, not all methods returning Boolean type have this notation.\nFor Boolean local variables or methods, it is highly recommended that you add non-meaningful prefixes, including is (commonly used by JavaBeans), has, can, should, and must. Modern integrated development environments (IDEs) such as Intellij are already capable of doing this for you when you generate getters in Java. For Kotlin, this process is even more straightforward as everything is on the byte-code level under the hood.\n\\textbf{Invalid example}:\n\\begin{lstlisting}[language=Kotlin]\nval isNoError: Boolean\nval isNotFound: Boolean\nfun empty()\nfun next();\n\\end{lstlisting}\n\\textbf{Valid example}:\n\\begin{lstlisting}[language=Kotlin]\nval isError: Boolean\nval isFound: Boolean\nval hasLicense: Boolean\nval canEvaluate: Boolean\nval shouldAbort: Boolean\nfun isEmpty()\nfun hasNext()\n\\end{lstlisting}\n\\section*{\\textbf{2. Comments}}\n\\label{sec:2.}\nThe best practice is to begin your code with a summary, which can be one sentence.\nTry to balance between writing no comments at all and obvious commentary statements for each line of code.\nComments should be accurately and clearly expressed, without repeating the name of the class, interface, or method.\nComments are not a solution to the wrong code. Instead, you should fix the code as soon as you notice an issue or plan to fix it (by entering a TODO comment, including a Jira number).\nComments should accurately reflect the code's design ideas and logic and further describe its business logic.\nAs a result, other programmers will be able to save time when trying to understand the code.\nImagine that you are writing the comments to help yourself to understand the original ideas behind the code in the future.\n\\subsection*{\\textbf{2.1 General form of Kdoc}}\n\\label{sec:2.1}\nKDoc is a combination of JavaDoc's block tags syntax (extended to support specific constructions of Kotlin) and Markdown's inline markup.\nThe basic format of KDoc is shown in the following example:\n\\begin{lstlisting}[language=Kotlin]\n /**\n * There are multiple lines of KDoc text,\n * Other ...\n */\nfun method(arg: String) {\n    // ...\n}\n\\end{lstlisting}\nIt is also shown in the following single-line form:\n\\begin{lstlisting}[language=Kotlin]\n /** Short form of KDoc. */\n\\end{lstlisting}\nUse a single-line form when you store the entire KDoc block in one line (and there is no KDoc mark @XXX). For detailed instructions on how to use KDoc, refer to \\href{https://docs.oracle.com/en/Kotlin/Kotlinse/11/tools/KDoc.html}{Official Document}.\n\\subsubsection*{\\textbf{2.1.1 Using KDoc for the public}}\n\\leavevmode\\newline\n\\label{sec:2.1.1}\nAt a minimum, KDoc should be used for every public, protected, or internal decorated class, interface, enumeration, method, and member field (property).\nOther code blocks can also have KDocs if needed.\nInstead of using comments or KDocs before properties in the primary constructor of a class - use \\textbf{@property} tag in a KDoc of a class.\nAll properties of the primary constructor should also be documented in a KDoc with a \\textbf{@property} tag.\n\\textbf{Incorrect example:}\n\\begin{lstlisting}[language=Kotlin]\n/**\n * Class description\n */\nclass Example(\n /**\n  * property description\n  */\n  val foo: Foo,\n  // another property description\n  val bar: Bar\n)\n\\end{lstlisting}\n\\textbf{Correct example:}\n\\begin{lstlisting}[language=Kotlin]\n/**\n * Class description\n * @property foo property description\n * @property bar another property description\n */\nclass Example(\n  val foo: Foo,\n  val bar: Bar\n)\n\\end{lstlisting}\n\\textbf{Exceptions:}\n* For setters/getters of properties, obvious comments (like \\textbf{this getter returns field}) are optional. Note that Kotlin generates simple \\textbf{get/set} methods under the hood.\n\n* It is optional to add comments for simple one-line methods, such as shown in the example below:\n\\begin{lstlisting}[language=Kotlin]\nval isEmpty: Boolean\n    get() = this.size == 0\n\\end{lstlisting}\nor\n\\begin{lstlisting}[language=Kotlin]\nfun isEmptyList(list: List<String>) = list.size == 0\n\\end{lstlisting}\n\\textbf{Note:} You can skip KDocs for a method's override if it is almost the same as the superclass method.\n\\subsubsection*{\\textbf{2.1.2 Describing methods that have arguments}}\n\\leavevmode\\newline\n\\label{sec:2.1.2}\nWhen the method has such details as arguments, return value, or can throw exceptions, it must be described in the KDoc block (with @param, @return, @throws, etc.).\n\\textbf{Valid examples:}\n\\begin{lstlisting}[language=Kotlin]\n/**\n * This is the short overview comment for the example interface.\n *     / * Add a blank line between the comment text and each KDoc tag underneath * /\n * @since 1.6\n */\n protected abstract class Sample {\n    /**\n     * This is a long comment with whitespace that should be split in\n     * comments on multiple lines if the line comment formatting is enabled.\n     *     / * Add a blank line between the comment text and each KDoc tag underneath * /\n     * @param fox A quick brown fox jumps over the lazy dog\n     * @return battle between fox and dog\n     */\n    protected abstract fun foo(Fox fox)\n     /**\n      * These possibilities include: Formatting of header comments\n      *     / * Add a blank line between the comment text and each KDoc tag underneath * /\n      * @return battle between fox and dog\n      * @throws ProblemException if lazy dog wins\n      */\n    protected fun bar() throws ProblemException {\n        // Some comments / * No need to add a blank line here * /\n        var aVar = ...\n        // Some comments  / * Add a blank line before the comment * /\n        fun doSome()\n    }\n }\n\\end{lstlisting}\n\\subsubsection*{\\textbf{2.1.3 Only one space between the Kdoc tag and content. Tags are arranged in the order.}}\n\\leavevmode\\newline\n\\label{sec:2.1.3}\nThere should be only one space between the Kdoc tag and content. Tags are arranged in the following order: @param, @return, and @throws.\nTherefore, Kdoc should contain the following:\n- Functional and technical description, explaining the principles, intentions, contracts, API, etc.\n- The function description and @tags (\\textbf{implSpec}, \\textbf{apiNote}, and \\textbf{implNote}) require an empty line after them.\n- \\textbf{@implSpec}: A specification related to API implementation, and it should let the implementer decide whether to override it.\n- \\textbf{@apiNote}: Explain the API precautions, including whether to allow null and whether the method is thread-safe, as well as the algorithm complexity, input, and output range, exceptions, etc.\n- \\textbf{@implNote}: A note related to API implementation, which implementers should keep in mind.\n- One empty line, followed by regular \\textbf{@param}, \\textbf{@return}, \\textbf{@throws}, and other comments.\n- The conventional standard \"block labels\" are arranged in the following order: \\textbf{@param}, \\textbf{@return}, \\textbf{@throws}.\nKdoc should not contain:\n- Empty descriptions in tag blocks. It is better not to write Kdoc than waste code line space.\n- There should be no empty lines between the method/class declaration and the end of Kdoc (\\textbf{*/} symbols).\n- \\textbf{@author} tag. It doesn't matter who originally created a class when you can use \\textbf{git blame} or VCS of your choice to look through the changes history.\nImportant notes:\n- KDoc does not support the \\textbf{@deprecated} tag. Instead, use the \\textbf{@Deprecated} annotation.\n- The \\textbf{@since} tag should be used for versions only. Do not use dates in \\textbf{@since} tag, it's confusing and less accurate.\nIf a tag block cannot be described in one line, indent the content of the new line by \\textit{four spaces} from the \\textbf{@} position to achieve alignment (\\textbf{@} counts as one + three spaces).\n\n\\textbf{Exception:}\n\nWhen the descriptive text in a tag block is too long to wrap, you can indent the alignment with the descriptive text in the last line. The descriptive text of multiple tags does not need to be aligned.\nSee [3.8 Horizontal space].\nIn Kotlin, compared to Java, you can put several classes inside one file, so each class should have a Kdoc formatted comment (as stated in rule 2.1).\nThis comment should contain @since tag. The right style is to write the application version when its functionality is released. It should be entered after the \\textbf{@since} tag.\n\\textbf{Examples:}\n\\begin{lstlisting}[language=Kotlin]\n/**\n * Description of functionality\n *\n * @since 1.6\n */\n\\end{lstlisting}\nOther KDoc tags (such as @param type parameters and @see.) can be added as follows:\n\\begin{lstlisting}[language=Kotlin]\n/**\n * Description of functionality\n *\n * @apiNote: Important information about API\n *\n * @since 1.6\n */\n\\end{lstlisting}\n\\subsection*{\\textbf{2.2 Adding comments on the file header}}\n\\label{sec:2.2}\nThis section describes the general rules of adding comments on the file header.\n\\subsubsection*{\\textbf{2.2.1 Formatting of comments in the file header}}\n\\leavevmode\\newline\n\\label{sec:2.2.1}\nComments on the file header should be placed before the package name and imports. If you need to add more content to the comment, subsequently add it in the same format.\nComments on the file header must include copyright information, without the creation date and author's name (use VCS for history management).\nAlso, describe the content inside files that contain multiple or no classes.\nThe following examples for Huawei describe the format of the \\textit{copyright license}: \\\nChinese version: \\textbf{版权所有 (c) 华为技术有限公司 2012-2020} \\\nEnglish version: \\textbf{Copyright (c) Huawei Technologies Co., Ltd. 2012-2020. All rights reserved.}\n\\textbf{2012} and \\textbf{2020} are the years the file was first created and the current year, respectively.\nDo not place \\textbf{release notes} in header, use VCS to keep track of changes in file. Notable changes can be marked in individual KDocs using \\textbf{@since} tag with version.\nInvalid example:\n\\begin{lstlisting}[language=Kotlin]\n/**\n * Release notes:\n * 2019-10-11: added class Foo\n */\nclass Foo\n\\end{lstlisting}\nValid example:\n\\begin{lstlisting}[language=Kotlin]\n/**\n * @since 2.4.0\n */\nclass Foo\n\\end{lstlisting}\n- The \\textbf{copyright statement} can use your company's subsidiaries, as shown in the below examples: \\\nChinese version: \\textbf{版权所有 (c) 海思半导体 2012-2020} \\\nEnglish version: \\textbf{Copyright (c) Hisilicon Technologies Co., Ltd. 2012-2020. All rights reserved.}\n- The copyright information should not be written in KDoc style or use single-line comments. It must start from the beginning of the file.\nThe following example is a copyright statement for Huawei, without other functional comments:\n\\begin{lstlisting}[language=Kotlin]\n/*\n * Copyright (c) Huawei Technologies Co., Ltd. 2012-2020. All rights reserved.\n */\n\\end{lstlisting}\nThe following factors should be considered when writing the file header or comments for top-level classes:\n- File header comments must start from the top of the file. If it is a top-level file comment, there should be a blank line after the last Kdoc \\textbf{*/} symbol. If it is a comment for a top-level class, the class declaration should start immediately without using a newline.\n- Maintain a unified format. The specific format can be formulated by the project (for example, if you use an existing opensource project), and you need to follow it.\n- A top-level file-Kdoc must include a copyright and functional description, especially if there is more than one top-level class.\n- Do not include empty comment blocks. If there is no content after the option \\textbf{@apiNote}, the entire tag block should be deleted.\n- The industry practice is not to include historical information in the comments. The corresponding history can be found in VCS (git, svn, etc.). Therefore, it is not recommended to include historical data in the comments of the Kotlin source code.\n\\subsection*{\\textbf{2.3 Comments on the function header}}\n\\label{sec:2.3}\nComments on the function header are placed above function declarations or definitions. A newline should not exist between a function declaration and its Kdoc. Use the preceding <<c2.1,KDoc>> style rules.\nAs stated in Chapter 1, the function name should reflect its functionality as much as possible. Therefore, in the Kdoc, try to describe the functionality that is not mentioned in the function name.\nAvoid unnecessary comments on dummy coding.\nThe function header comment's content is optional, but not limited to function description, return value, performance constraints, usage, memory conventions, algorithm implementation, reentrant requirements, etc.\n\\subsection*{\\textbf{2.4 Code comments}}\n\\label{sec:2.4}\nThis section describes the general rules of adding code comments.\n\\subsubsection*{\\textbf{2.4.1 Add a blank line between the body of the comment and Kdoc tag-blocks.}}\n\\leavevmode\\newline\n\\label{sec:2.4.1}\nIt is a good practice to add a blank line between the body of the comment and Kdoc tag-blocks. Also, consider the following rules:\n- There must be one space between the comment character and the content of the comment.\n- There must be a newline between a Kdoc and the presiding code.\n- An empty line should not exist between a Kdoc and the code it is describing. You do not need to add a blank line before the first comment in a particular namespace (code block) (for example, between the function declaration and first comment in a function body).\n\\textbf{Valid Examples:}\n\\begin{lstlisting}[language=Kotlin]\n/**\n * This is the short overview comment for the example interface.\n *\n * @since 1.6\n */\n public interface Example {\n    // Some comments  /* Since it is the first member definition in this code block, there is no need to add a blank line here */\n    val aField: String = ...\n                     /* Add a blank line above the comment */\n    // Some comments\n    val bField: String = ...\n                      /* Add a blank line above the comment */\n    /**\n     * This is a long comment with whitespace that should be split in\n     * multiple line comments in case the line comment formatting is enabled.\n     *                /* blank line between description and Kdoc tag */\n     * @param fox A quick brown fox jumps over the lazy dog\n     * @return the rounds of battle of fox and dog\n     */\n    fun foo(Fox fox)\n                      /* Add a blank line above the comment */\n     /**\n      * These possibilities include: Formatting of header comments\n      *\n      * @return the rounds of battle of fox and dog\n      * @throws ProblemException if lazy dog wins\n      */\n    fun bar() throws ProblemException {\n        // Some comments  /* Since it is the first member definition in this range, there is no need to add a blank line here */\n        var aVar = ...\n        // Some comments  /* Add a blank line above the comment */\n        fun doSome()\n    }\n }\n\\end{lstlisting}\n- Leave one single space between the comment on the right side of the code and the code.\nIf you use conditional comments in the \\textbf{if-else-if} scenario, put the comments inside the \\textbf{else-if} branch or in the conditional block, but not before the \\textbf{else-if}. This makes the code more understandable.\nWhen the if-block is used with curly braces, the comment should be placed on the next line after opening the curly braces.\nCompared to Java, the \\textbf{if} statement in Kotlin statements returns a value. For this reason, a comment block can describe a whole \\textbf{if-statement}.\n\\textbf{Valid examples:}\n\\begin{lstlisting}[language=Kotlin]\nval foo = 100  // right-side comment\nval bar = 200  /* right-side comment */\n// general comment for the value and whole if-else condition\nval someVal = if (nr % 15 == 0) {\n    // when nr is a multiple of both 3 and 5\n    println(\"fizzbuzz\")\n} else if (nr % 3 == 0) {\n    // when nr is a multiple of 3, but not 5\n    // We print \"fizz\", only.\n    println(\"fizz\")\n} else if (nr % 5 == 0) {\n    // when nr is a multiple of 5, but not 3\n    // we print \"buzz\" only.\n    println(\"buzz\")\n} else {\n    // otherwise, we print the number.\n    println(x)\n}\n\\end{lstlisting}\n- Start all comments (including KDoc) with a space after the first symbol (\\textbf{//}, \\textbf{/*}, \\textbf{/} and \\textbf{*})\n\\textbf{Valid example:}\n\\begin{lstlisting}[language=Kotlin]\nval x = 0  // this is a comment\n\\end{lstlisting}\n\\subsubsection*{\\textbf{2.4.2 Do not comment on unused code blocks}}\n\\leavevmode\\newline\n\\label{sec:2.4.2}\nDo not comment on unused code blocks, including imports. Delete these code blocks immediately.\nA code is not used to store history. Git, svn, or other VCS tools should be used for this purpose.\nUnused imports increase the coupling of the code and are not conducive to maintenance. The commented out code cannot be appropriately maintained.\nIn an attempt to reuse the code, there is a high probability that you will introduce defects that are easily missed.\nThe correct approach is to delete the unnecessary code directly and immediately when it is not used anymore.\nIf you need the code again, consider porting or rewriting it as changes could have occurred since you first commented on the code.\n\\subsubsection*{\\textbf{2.4.3 Code delivered to the client should not contain TODO}}\n\\leavevmode\\newline\n\\label{sec:2.4.3}\nThe code officially delivered to the client typically should not contain TODO/FIXME comments.\n\\textbf{TODO} comments are typically used to describe modification points that need to be improved and added. For example, refactoring FIXME comments are typically used to describe known defects and bugs that will be subsequently fixed and are not critical for an application.\nThey should all have a unified style to facilitate unified text search processing.\n\\textbf{Example:}\n\\begin{lstlisting}[language=Kotlin]\n// TODO(<author-name>): Jira-XXX - support new json format\n// FIXME: Jira-XXX - fix NPE in this code block\n\\end{lstlisting}\nAt a version development stage, these annotations can be used to highlight the issues in the code, but all of them should be fixed before a new product version is released.\n\\section*{\\textbf{3. General formatting}}\n\\label{sec:3.}\n\\subsection*{\\textbf{3.1 File-related rules}}\n\\label{sec:3.1}\nThis section describes the rules related to using files in your code.\n\\subsubsection*{\\textbf{3.1.1 Avoid files that are too long}}\n\\leavevmode\\newline\n\\label{sec:3.1.1}\nIf the file is too long and complicated, it should be split into smaller files, functions, or modules. Files should not exceed 2000 lines (non-empty and non-commented lines).\nIt is recommended to horizontally or vertically split the file according to responsibilities or hierarchy of its parts.\nThe only exception to this rule is code generation - the auto-generated files that are not manually modified can be longer.\n\\subsubsection*{\\textbf{3.1.2 Code blocks in the source file should be separated by one blank line}}\n\\leavevmode\\newline\n\\label{sec:3.1.2}\nA source file contains code blocks in the following order: copyright, package name, imports, and top-level classes. They should be separated by one blank line.\na) Code blocks should be in the following order:\n1.\tKdoc for licensed or copyrighted files\n2.\t\\textbf{@file} annotation\n3.\tPackage name\n4.\tImport statements\n5.\tTop-class header and top-function header comments\n6.\tTop-level classes or functions\nb) Each of the preceding code blocks should be separated by a blank line.\nc) Import statements are alphabetically arranged, without using line breaks and wildcards ( wildcard imports - \\textbf{*}).\nd) \\textbf{Recommendation}: One \\textbf{.kt} source file should contain only one class declaration, and its name should match the filename\ne) Avoid empty files that do not contain the code or contain only imports/comments/package name\nf) Unused imports should be removed\n\\subsubsection*{\\textbf{3.1.3 Import statements order}}\n\\leavevmode\\newline\n\\label{sec:3.1.3}\nFrom top to bottom, the order is the following:\n1. Android\n2. Imports of packages used internally in your organization\n3. Imports from other non-core dependencies\n4. Java core packages\n5. kotlin stdlib\nEach category should be alphabetically arranged. Each group should be separated by a blank line. This style is compatible with  \\href{https://source.android.com/setup/contribute/code-style#order-import-statements}{Android import order}.\n\\textbf{Valid example}:\n\\begin{lstlisting}[language=Kotlin]\nimport android.* // android\nimport androidx.* // android\nimport com.android.* // android\nimport com.your.company.* // your company's libs\nimport your.company.* // your company's libs\nimport com.fasterxml.jackson.databind.ObjectMapper // other third-party dependencies\nimport org.junit.jupiter.api.Assertions\nimport java.io.IOException // java core packages\nimport java.net.URL\nimport kotlin.system.exitProcess  // kotlin standard library\nimport kotlinx.coroutines.*  // official kotlin extension library\n\\end{lstlisting}\n\\subsubsection*{\\textbf{3.1.4 Order of declaration parts of class-like code structures}}\n\\leavevmode\\newline\n\\label{sec:3.1.4}\nThe declaration parts of class-like code structures (class, interface, etc.) should be in the following order: compile-time constants (for objects), class properties, late-init class properties, init-blocks, constructors, public methods, internal methods, protected methods, private methods, and companion object. Blank lines should separate their declaration.\nNotes:\n1.\tThere should be no blank lines between properties with the following \\textbf{exceptions}: when there is a comment before a property on a separate line or annotations on a separate line.\n2.\tProperties with comments/Kdoc should be separated by a newline before the comment/Kdoc.\n3.\tEnum entries and constant properties (\\textbf{const val}) in companion objects should be alphabetically arranged.\nThe declaration part of a class or interface should be in the following order:\n- Compile-time constants (for objects)\n- Properties\n- Late-init class properties\n- Init-blocks\n- Constructors\n- Methods or nested classes. Put nested classes next to the code they are used by.\nIf the classes are meant to be used externally, and are not referenced inside the class, put them after the companion object.\n- Companion object\n\\textbf{Exception:}\nAll variants of a \\textbf{(private) val} logger should be placed at the beginning of the class (\\textbf{(private) val log}, \\textbf{LOG}, \\textbf{logger}, etc.).\n\\subsubsection*{\\textbf{3.1.5 Order of declaration of top-level code structures}}\n\\leavevmode\\newline\n\\label{sec:3.1.5}\nKotlin allows several top-level declaration types: classes, objects, interfaces, properties and functions.\nWhen declaring more than one class or zero classes (e.g. only functions), as per rule [2.2.1], you should document the whole file in the header KDoc.\nWhen declaring top-level structures, keep the following order:\n1. Top-level constants and properties (following same order as properties inside a class: \\textbf{const val},\\textbf{val}, \\textbf{lateinit var}, \\textbf{var})\n2. Interfaces, classes and objects (grouped by their visibility modifiers)\n3. Extension functions\n4. Other functions\n\\textbf{Note}:\nExtension functions shouldn't have receivers declared in the same file according to [rule 6.2.3]\nValid example:\n\\begin{lstlisting}[language=Kotlin]\npackage com.saveourtool.diktat.example\nconst val CONSTANT = 42\nval topLevelProperty = \"String constant\"\ninterface IExample\nclass Example : IExample\nprivate class Internal\nfun Other.asExample(): Example { /* ... */ }\nprivate fun Other.asInternal(): Internal { /* ... */ }\nfun doStuff() { /* ... */ }\n\\end{lstlisting}\n\\textbf{Note}:\nkotlin scripts (.kts) allow arbitrary code to be placed on the top level. When writing kotlin scripts, you should first declare all properties, classes\nand functions. Only then you should execute functions on top level. It is still recommended wrapping logic inside functions and avoid using top-level statements\nfor function calls or wrapping blocks of code in top-level scope functions like \\textbf{run}.\nExample:\n\\begin{lstlisting}[language=Kotlin]\n/* class declarations */\n/* function declarations */\nrun {\n    // call functions here\n}\n\\end{lstlisting}\n\\subsection*{\\textbf{3.2 Braces}}\n\\label{sec:3.2}\nThis section describes the general rules of using braces in your code.\n\\subsubsection*{\\textbf{3.2.1 Using braces in conditional statements and loop blocks}}\n\\leavevmode\\newline\n\\label{sec:3.2.1}\nBraces should always be used in \\textbf{if}, \\textbf{else}, \\textbf{for}, \\textbf{do}, and \\textbf{while} statements, even if the program body is empty or contains only one statement. In special Kotlin \\textbf{when} statements, you do not need to use braces for single-line statements.\n\\textbf{Valid example:}\n\\begin{lstlisting}[language=Kotlin]\nwhen (node.elementType) {\n    FILE -> {\n        checkTopLevelDoc(node)\n        checkSomething()\n     }\n    CLASS -> checkClassElements(node)\n}\n\\end{lstlisting}\n\\textbf{Exception:} The only exception is ternary operator in Kotlin (a single line \\textbf{if () <> else <>} )\n\\textbf{Invalid example:}\n\\begin{lstlisting}[language=Kotlin]\nval value = if (string.isEmpty())  // WRONG!\n                0\n            else\n                1\n\\end{lstlisting}\n\\textbf{Valid example}:\n\\begin{lstlisting}[language=Kotlin]\nval value = if (string.isEmpty()) 0 else 1  // Okay\n\\end{lstlisting}\n\\begin{lstlisting}[language=Kotlin]\nif (condition) {\n    println(\"test\")\n} else {\n    println(0)\n}\n\\end{lstlisting}\n\\subsubsection*{\\textbf{3.2.2  Opening braces are placed at the end of the line in}}\n\\leavevmode\\newline\n\\label{sec:3.2.2}\nFor *non-empty* blocks and block structures, the opening brace is placed at the end of the line.\nFollow the K\\&R style (1TBS or OTBS) for *non-empty* code blocks with braces:\n- The opening brace and first line of the code block are on the same line.\n- The closing brace is on its own new line.\n- The closing brace can be followed by a newline character. The only exceptions are \\textbf{else}, \\textbf{finally}, and \\textbf{while} (from \\textbf{do-while} statement), or \\textbf{catch} keywords.\nThese keywords should not be split from the closing brace by a newline character.\n\\textbf{Exception cases}:\n1) For lambdas, there is no need to put a newline character after the first (function-related) opening brace. A newline character should appear only after an arrow (\\textbf{->}) (see [point 5 of Rule 3.6.2]).\n\\begin{lstlisting}[language=Kotlin]\narg.map { value ->\n    foo(value)\n}\n\\end{lstlisting}\n2) for \\textbf{else}/\\textbf{catch}/\\textbf{finally}/\\textbf{while} (from \\textbf{do-while} statement) keywords closing brace should stay on the same line:\n\\begin{lstlisting}[language=Kotlin]\ndo {\n    if (true) {\n        x++\n    } else {\n        x--\n    }\n} while (x > 0)\n\\end{lstlisting}\n\n\\textbf{Valid example:}\n\\begin{lstlisting}[language=Kotlin]\n        return arg.map { value ->\n            while (condition()) {\n                method()\n            }\n            value\n        }\n        return MyClass() {\n            @Override\n              fun method() {\n                if (condition()) {\n                    try {\n                        something()\n                    } catch (e: ProblemException) {\n                        recover()\n                    }\n                } else if (otherCondition()) {\n                    somethingElse()\n                } else {\n                    lastThing()\n                }\n            }\n        }\n\\end{lstlisting}\n\\subsection*{\\textbf{3.3 Indentation}}\n\\label{sec:3.3}\nOnly spaces are permitted for indentation, and each indentation should equal \\textbf{four spaces} (tabs are not permitted).\nIf you prefer using tabs, simply configure them to change to spaces in your IDE automatically.\nThese code blocks should be indented if they are placed on the new line, and the following conditions are met:\n-\tThe code block is placed immediately after an opening brace.\n-\tThe code block is placed after each operator, including the assignment operator (\\textbf{+}/\\textbf{-}/\\textbf{\\&\\&}/\\textbf{=}/etc.)\n-\tThe code block is a call chain of methods:\n\\begin{lstlisting}[language=Kotlin]\nsomeObject\n    .map()\n    .filter()\n\\end{lstlisting}\n-  The code block is placed immediately after the opening parenthesis.\n-  The code block is placed immediately after an arrow in lambda:\n\\begin{lstlisting}[language=Kotlin]\narg.map { value ->\n    foo(value)\n}\n\\end{lstlisting}\n\n\\textbf{Exceptions}:\n1.\tArgument lists: \\\na) Eight spaces are used to indent argument lists (both in declarations and at call sites). \\\nb) Arguments in argument lists can be aligned if they are on different lines.\n2.\tEight spaces are used if there is a newline after any binary operator.\n3.\tEight spaces are used for functional-like styles when the newline is placed before the dot.\n4.\tSupertype lists: \\\na) Four spaces are used if the colon before the supertype list is on a new line. \\\nb) Four spaces are used before each supertype, and eight spaces are used if the colon is on a new line.\n\\textbf{Note:} there should be an indentation after all statements such as \\textbf{if}, \\textbf{for}, etc. However, according to this code style, such statements require braces.\n\\begin{lstlisting}[language=Kotlin]\nif (condition)\n    foo()\n\\end{lstlisting}\n\\textbf{Exceptions}:\n- When breaking the parameter list of a method/class constructor, it can be aligned with \\textbf{8 spaces}. A parameter that was moved to a new line can be on the same level as the previous argument:\n\n\\begin{lstlisting}[language=Kotlin]\nfun visit(\n        node: ASTNode,\n        autoCorrect: Boolean,\n        params: KtLint.ExperimentalParams,\n        emit: (offset: Int, errorMessage: String, canBeAutoCorrected: Boolean) -> Unit\n) {\n}\n\\end{lstlisting}\n\n- Such operators as \\textbf{+}/\\textbf{-}/\\textbf{*} can be indented with \\textbf{8 spaces}:\n\n\\begin{lstlisting}[language=Kotlin]\nval abcdef = \"my splitted\" +\n                \" string\"\n\\end{lstlisting}\n\n- A list of supertypes should be indented with \\textbf{4 spaces} if they are on different lines or with \\textbf{8 spaces} if the leading colon is also on a separate line\n\\begin{lstlisting}[language=Kotlin]\nclass A :\n    B()\n\nclass A\n    :\n        B()\n\\end{lstlisting}\n\\subsection*{\\textbf{3.4 Empty blocks}}\n\\label{sec:3.4}\nAvoid empty blocks, and ensure braces start on a new line. An empty code block can be closed immediately on the same line and the next line. However, a newline is recommended between opening and closing braces \\textbf{\\{\\}} (see the examples below.)\nGenerally, empty code blocks are prohibited; using them is considered a bad practice (especially for catch block).\nThey are only appropriate for overridden functions when the base class's functionality is not needed in the class-inheritor.\n\\begin{lstlisting}[language=Kotlin]\noverride fun foo() {\n}\n\\end{lstlisting}\n\\textbf{Valid examples} (note once again that generally empty blocks are prohibited):\n\\begin{lstlisting}[language=Kotlin]\nfun doNothing() {}\nfun doNothingElse() {\n}\n\\end{lstlisting}\n\\textbf{Invalid examples:}\n\\begin{lstlisting}[language=Kotlin]\ntry {\n  doSomething()\n} catch (e: Some) {}\n\\end{lstlisting}\nUse the following valid code instead:\n\\begin{lstlisting}[language=Kotlin]\ntry {\n   doSomething()\n} catch (e: Some) {\n}\n\\end{lstlisting}\n\\subsection*{\\textbf{3.5 Line length}}\n\\label{sec:3.5}\nLine length should be less than 120 symbols. The international code style prohibits \\textbf{non-Latin} (\\textbf{non-ASCII}) symbols.\n(See [Identifiers]) However, if you still intend on using them, follow the following convention:\n- One wide character occupies the width of two narrow characters.\nThe \"wide\" and \"narrow\" parts of a character are defined by its \\href{https://unicode.org/reports/tr11/}{east Asian width Unicode attribute}.\nTypically, narrow characters are also called \"half-width\" characters.\nAll characters in the ASCII character set include letters (such as \\textbf{a, A}), numbers (such as \\textbf{0, 3}), and punctuation spaces (such as \\textbf{,} , \\textbf{\\{}), all of which are narrow characters.\nWide characters are also called \"full-width\" characters. Chinese characters (such as \\textbf{中, 文}), Chinese punctuation (\\textbf{，} , \\textbf{；} ), full-width letters and numbers (such as \\textbf{Ａ、３}) are \"full-width\" characters.\nEach one of these characters represents two narrow characters.\n- Any line that exceeds this limit (\\textbf{120 narrow symbols}) should be wrapped, as described in the [Newline section].\n\\textbf{Exceptions:}\n1.\tThe long URL or long JSON method reference in KDoc.\n2.\tThe \\textbf{package} and \\textbf{import} statements.\n3.\tThe command line in the comment, enabling it to be cut and pasted into the shell for use.\n\\subsection*{\\textbf{3.6 Line breaks}}\n\\label{sec:3.6}\nThis section contains the rules and recommendations on using line breaks.\n\\subsubsection*{\\textbf{3.6.1 Each line can have a maximum of one statement}}\n\\leavevmode\\newline\n\\label{sec:3.6.1}\nEach line can have a maximum of one code statement. This recommendation prohibits the use of code with \\textbf{;} because it decreases code visibility.\n\\textbf{Invalid example:}\n\\begin{lstlisting}[language=Kotlin]\nval a = \"\"; val b = \"\"\n\\end{lstlisting}\n\\textbf{Valid example:}\n\\begin{lstlisting}[language=Kotlin]\nval a = \"\"\nval b = \"\"\n\\end{lstlisting}\n\\subsubsection*{\\textbf{3.6.2 Rules for line-breaking}}\n\\leavevmode\\newline\n\\label{sec:3.6.2}\n1) Unlike Java, Kotlin allows you not to put a semicolon (\\textbf{;}) after each statement separated by a newline character.\n    There should be no redundant semicolon at the end of the lines.\n\nWhen a newline character is needed to split the line, it should be placed after such operators as \\textbf{\\&\\&}/\\textbf{||}/\\textbf{+}/etc. and all infix functions (for example, \\textbf{xor}).\nHowever, the newline character should be placed before operators such as \\textbf{.}, \\textbf{?.}, \\textbf{?:}, and \\textbf{::}.\nNote that all comparison operators, such as \\textbf{==}, \\textbf{>}, \\textbf{<}, should not be split.\n\\textbf{Invalid example}:\n\\begin{lstlisting}[language=Kotlin]\n     if (node !=\n             null && test != null) {}\n\\end{lstlisting}\n\n\\textbf{Valid example}:\n\\begin{lstlisting}[language=Kotlin]\n         if (node != null &&\n                 test != null) {\n         }\n\\end{lstlisting}\n\n\\textbf{Note:} You need to follow the functional style, meaning each function call in a chain with \\textbf{.} should start at a new line if the chain of functions contains more than one call:\n\\begin{lstlisting}[language=Kotlin]\n  val value = otherValue!!\n          .map { x -> x }\n          .filter {\n              val a = true\n              true\n          }\n          .size\n\\end{lstlisting}\n\\textbf{Note:} The parser prohibits the separation of the \\textbf{!!} operator from the value it is checking.\n\\textbf{Exception}: If a functional chain is used inside the branches of a ternary operator, it does not need to be split with newlines.\n\\textbf{Valid example}:\n\\begin{lstlisting}[language=Kotlin]\nif (condition) list.map { foo(it) }.filter { bar(it) } else list.drop(1)\n\\end{lstlisting}\n\\textbf{Note:} If dot qualified expression is inside condition or passed as an argument - it should be replaced with new variable.\n\\textbf{Invalid example}:\n\\begin{lstlisting}[language=Kotlin]\n if (node.treeParent.treeParent.findChildByType(IDENTIFIER) != null) {}\n\\end{lstlisting}\n\n\\textbf{Valid example}:\n\\begin{lstlisting}[language=Kotlin]\n        val grandIdentifier = node\n            .treeParent\n            .treeParent\n            .findChildByType(IDENTIFIER)\n        if (grandIdentifier != null) {}\n\\end{lstlisting}\n\n2)\tNewlines should be placed after the assignment operator (\\textbf{=}).\n3)\tIn function or class declarations, the name of a function or constructor should not be split by a newline from the opening brace \\textbf{(}.\n    A brace should be placed immediately after the name without any spaces in declarations or at call sites.\n4)\tNewlines should be placed right after the comma (\\textbf{,}).\n5)\tIf a lambda statement contains more than one line in its body, a newline should be placed after an arrow if the lambda statement has explicit parameters.\n    If it uses an implicit parameter (\\textbf{it}), the newline character should be placed after the opening brace (\\textbf{\\{}).\n    The following examples illustrate this rule:\n\\textbf{Invalid example:}\n\\begin{lstlisting}[language=Kotlin]\n    value.map { name -> foo()\n        bar()\n    }\n\\end{lstlisting}\n\\textbf{Valid example:}\n\\begin{lstlisting}[language=Kotlin]\nvalue.map { name ->\n    foo()\n    bar()\n}\nval someValue = { node:String -> node }\n\\end{lstlisting}\n6) When the function contains only a single expression, it can be written as \\href{https://kotlinlang.org/docs/reference/functions.html#single-expression-functions}{expression function}.\n   The below example shows the style that should not be used.\n\nInstead of:\n\\begin{lstlisting}[language=Kotlin]\noverride fun toString(): String { return \"hi\" }\n\\end{lstlisting}\nuse:\n\\begin{lstlisting}[language=Kotlin]\noverride fun toString() = \"hi\"\n\\end{lstlisting}\n7)  If an argument list in a function declaration (including constructors) or function call contains more than two arguments, these arguments should be split by newlines in the following style.\n\\textbf{Valid example:}\n\\begin{lstlisting}[language=Kotlin]\nclass Foo(val a: String,\n          b: String,\n          val c: String) {\n}\nfun foo(\n        a: String,\n        b: String,\n        c: String\n) {\n}\n\\end{lstlisting}\nIf and only if the first parameter is on the same line as an opening parenthesis, all parameters can be horizontally aligned by the first parameter.\nOtherwise, there should be a line break after an opening parenthesis.\nKotlin 1.4 introduced a trailing comma as an optional feature, so it is generally recommended to place all parameters on a separate line\nand append \\href{https://kotlinlang.org/docs/reference/whatsnew14.html#trailing-comma}{trailing comma}.\nIt makes the resolving of merge conflicts easier.\n\\textbf{Valid example:}\n\\begin{lstlisting}[language=Kotlin]\nfun foo(\n        a: String,\n        b: String,\n) {\n}\n\\end{lstlisting}\nsame should be done for function calls/constructor arguments/e.t.c\nKotlin supports trailing commas in the following cases:\nEnumerations\nValue arguments\nClass properties and parameters\nFunction value parameters\nParameters with optional type (including setters)\nIndexing suffix\nLambda parameters\nwhen entry\nCollection literals (in annotations)\nType arguments\nType parameters\nDestructuring declarations\n8) If the supertype list has more than two elements, they should be separated by newlines.\n\\textbf{Valid example:}\n\\begin{lstlisting}[language=Kotlin]\nclass MyFavouriteVeryLongClassHolder :\n    MyLongHolder<MyFavouriteVeryLongClass>(),\n    SomeOtherInterface,\n    AndAnotherOne { }\n\\end{lstlisting}\n\\subsection*{\\textbf{3.7 Using blank lines}}\n\\label{sec:3.7}\nReduce unnecessary blank lines and maintain a compact code size. By reducing unnecessary blank lines, you can display more code on one screen, which improves code readability.\n- Blank lines should separate content based on relevance and should be placed between groups of fields, constructors, methods, nested classes, \\textbf{init} blocks, and objects (see [3.1.2]).\n- Do not use more than one line inside methods, type definitions, and initialization expressions.\n- Generally, do not use more than two consecutive blank lines in a row.\n- Do not put newlines in the beginning or end of code blocks with curly braces.\n\\textbf{Valid example:}\n\\begin{lstlisting}[language=Kotlin]\nfun baz() {\n\n    doSomething()  // No need to add blank lines at the beginning and end of the code block\n    // ...\n}\n\\end{lstlisting}\n\\subsection*{\\textbf{3.8 Horizontal space}}\n\\label{sec:3.8}\nThis section describes general rules and recommendations for using spaces in the code.\n\\subsubsection*{\\textbf{3.8.1: Usage of whitespace for code separation}}\n\\leavevmode\\newline\n\\label{sec:3.8.1}\nFollow the recommendations below for using space to separate keywords:\n\\textbf{Note:} These recommendations are for cases where symbols are located on the same line. However, in some cases, a line break could be used instead of a space.\n1.  Separate keywords (such as \\textbf{if}, \\textbf{when}, \\textbf{for}) from the opening parenthesis with single whitespace.\n    The only exception is the \\textbf{constructor} keyword, which should not be separated from the opening parenthesis.\n2.  Separate keywords like \\textbf{else} or \\textbf{try} from the opening brace (\\textbf{\\{}) with single whitespace.\n    If \\textbf{else} is used in a ternary-style statement without braces, there should be a single space between \\textbf{else} and the statement after: \\textbf{if (condition) foo() else bar()}\n3.  Use a \\textbf{single} whitespace before all opening braces (\\textbf{\\{}). The only exception is the passing of a lambda as a parameter inside parentheses:\n\\begin{lstlisting}[language=Kotlin]\n     private fun foo(a: (Int) -> Int, b: Int) {}\n     foo({x: Int -> x}, 5) // no space before '{'\n\\end{lstlisting}\n4.  Single whitespace should be placed on both sides of binary operators. This also applies to operator-like symbols.\n    For example:\n\n - A colon in generic structures with the \\textbf{where} keyword:  \\textbf{where T : Type}\n - Arrow in lambdas: \\textbf{(str: String) -> str.length()}\n\\textbf{Exceptions:}\n- Two colons (\\textbf{::}) are written without spaces:\\\n  \\textbf{Object::toString}\n- The dot separator (\\textbf{.}) that stays on the same line with an object name:\\\n  \\textbf{object.toString()}\n- Safe access modifiers \\textbf{?.} and \\textbf{!!} that stay on the same line with an object name:\\\n  \\textbf{object?.toString()}\n- Operator \\textbf{..} for creating ranges:\\\n  \\textbf{1..100}\n5.  Use spaces after (\\textbf{,}), (\\textbf{:}), and (\\textbf{;}), except when the symbol is at the end of the line.\n    However, note that this code style prohibits the use of (\\textbf{;}) in the middle of a line ([see 3.3.2]).\n    There should be no whitespaces at the end of a line.\n    The only scenario where there should be no space after a colon is when the colon is used in the annotation to specify a use-site target (for example, \\textbf{@param:JsonProperty}).\n    There should be no spaces before \\textbf{,} , \\textbf{:} and \\textbf{;}.\n\n    \\textbf{Exceptions} for spaces and colons:\n\n    - When \\textbf{:} is used to separate a type and a supertype, including an anonymous object (after object keyword)\n    - When delegating to a superclass constructor or different constructor of the same class\n\\textbf{Valid example:}\n\\begin{lstlisting}[language=Kotlin]\n  abstract class Foo<out T : Any> : IFoo { }\n\n  class FooImpl : Foo() {\n      constructor(x: String) : this(x) { /*...*/ }\n\n      val x = object : IFoo { /*...*/ }\n  }\n\\end{lstlisting}\n6. There should be \\textit{only one space} between the identifier and its type: \\textbf{list: List<String>}\nIf the type is nullable, there should be no space before \\textbf{?}.\n7. When using \\textbf{[]} operator (\\textbf{get/set}) there should be \\textbf{no} spaces between identifier and \\textbf{[} : \\textbf{someList[0]}.\n8. There should be no space between a method or constructor name (both at declaration and at call site) and a parenthesis:\n   \\textbf{foo() \\{\\}}. Note that this sub-rule is related only to spaces; the rules for whitespaces are described in [see 3.6.2].\n    This rule does not prohibit, for example, the following code:\n\\begin{lstlisting}[language=Kotlin]\nfun foo\n(\n    a: String\n)\n\\end{lstlisting}\n9. Never put a space after \\textbf{(}, \\textbf{[}, \\textbf{<} (when used as a bracket in templates) or before \\textbf{)}, \\textbf{]}, \\textbf{>} (when used as a bracket in templates).\n10. There should be no spaces between a prefix/postfix operator (like \\textbf{!!} or \\textbf{++}) and its operand.\n\\subsubsection*{\\textbf{3.8.2: No spaces for horizontal alignment}}\n\\leavevmode\\newline\n\\label{sec:3.8.2}\n\\textit{Horizontal alignment} refers to aligning code blocks by adding space to the code. Horizontal alignment should not be used because:\n- When modifying code, it takes much time for new developers to format, support, and fix alignment issues.\n- Long identifier names will break the alignment and lead to less presentable code.\n- There are more disadvantages than advantages in alignment. To reduce maintenance costs, misalignment (???) is the best choice.\nRecommendation: Alignment only looks suitable for \\textbf{enum class}, where it can be used in table format to improve code readability:\n\\begin{lstlisting}[language=Kotlin]\nenum class Warnings(private val id: Int, private val canBeAutoCorrected: Boolean, private val warn: String) : Rule {\n    PACKAGE_NAME_MISSING         (1, true,  \"no package name declared in a file\"),\n    PACKAGE_NAME_INCORRECT_CASE  (2, true,  \"package name should be completely in a lower case\"),\n    PACKAGE_NAME_INCORRECT_PREFIX(3, false, \"package name should start from the company's domain\")\n    ;\n}\n\\end{lstlisting}\n\\textbf{Valid example:}\n\\begin{lstlisting}[language=Kotlin]\n private val nr: Int // no alignment, but looks fine\n private var color: Color // no alignment\n\\end{lstlisting}\n\\textbf{Invalid example}:\n\\begin{lstlisting}[language=Kotlin]\n private val    nr: Int    // aligned comment with extra spaces\n private val color: Color  // alignment for a comment and alignment for identifier name\n\\end{lstlisting}\n\\subsection*{\\textbf{3.9 Enumerations}}\n\\label{sec:3.9}\nEnum values are separated by a comma and line break, with ';' placed on the new line.\n1) The comma and line break characters separate enum values. Put \\textbf{;} on the new line:\n\\begin{lstlisting}[language=Kotlin]\nenum class Warnings {\n    A,\n    B,\n    C,\n    ;\n}\n\\end{lstlisting}\nThis will help to resolve conflicts and reduce the number of conflicts during merging pull requests.\nAlso, use \\href{https://kotlinlang.org/docs/reference/whatsnew14.html#trailing-comma}{trailing comma}.\n2) If the enum is simple (no properties, methods, and comments inside), you can declare it in a single line:\n\\begin{lstlisting}[language=Kotlin]\nenum class Suit { CLUBS, HEARTS, SPADES, DIAMONDS }\n\\end{lstlisting}\n3) Enum classes take preference (if it is possible to use it). For example, instead of two boolean properties:\n\\begin{lstlisting}[language=Kotlin]\nval isCelsius = true\nval isFahrenheit = false\n\\end{lstlisting}\nuse enum class:\n\\begin{lstlisting}[language=Kotlin]\nenum class TemperatureScale { CELSIUS, FAHRENHEIT }\n\\end{lstlisting}\n- The variable value only changes within a fixed range and is defined with the enum type.\n- Avoid comparison with magic numbers of \\textbf{-1, 0, and 1}; use enums instead.\n\\begin{lstlisting}[language=Kotlin]\nenum class ComparisonResult {\n    ORDERED_ASCENDING,\n    ORDERED_SAME,\n    ORDERED_DESCENDING,\n    ;\n}\n\\end{lstlisting}\n\\subsection*{\\textbf{3.10 Variable declaration}}\n\\label{sec:3.10}\nThis section describes rules for the declaration of variables.\n\\subsubsection*{\\textbf{3.10.1 Declare one variable per line}}\n\\leavevmode\\newline\n\\label{sec:3.10.1}\nEach property or variable must be declared on a separate line.\n\\textbf{Invalid example}:\n\\begin{lstlisting}[language=Kotlin]\nval n1: Int; val n2: Int\n\\end{lstlisting}\n\\subsubsection*{\\textbf{3.10.2 Variables should be declared near the line where they are first used}}\n\\leavevmode\\newline\n\\label{sec:3.10.2}\nDeclare local variables close to the point where they are first used to minimize their scope. This will also increase the readability of the code.\nLocal variables are usually initialized during their declaration or immediately after.\nThe member fields of the class should be declared collectively (see [Rule 3.1.2] for details on the class structure).\n\\subsection*{\\textbf{3.11 'When' expression}}\n\\label{sec:3.11}\nThe \\textbf{when} statement must have an 'else' branch unless the condition variable is enumerated or a sealed type.\nEach \\textbf{when} statement should contain an \\textbf{else} statement group, even if it does not contain any code.\n\\textbf{Exception:} If 'when' statement of the \\textbf{enum or sealed} type contains all enum values, there is no need to have an \"else\" branch.\nThe compiler can issue a warning when it is missing.\n\\subsection*{\\textbf{3.12 Annotations}}\n\\label{sec:3.12}\nEach annotation applied to a class, method or constructor should be placed on its own line. Consider the following examples:\n1. Annotations applied to the class, method or constructor are placed on separate lines (one annotation per line).\n\\textbf{Valid example}:\n\\begin{lstlisting}[language=Kotlin]\n@MustBeDocumented\n@CustomAnnotation\nfun getNameIfPresent() { /* ... */ }\n\\end{lstlisting}\n2. A single annotation should be on the same line as the code it is annotating.\n\\textbf{Valid example}:\n\\begin{lstlisting}[language=Kotlin]\n@CustomAnnotation class Foo {}\n\\end{lstlisting}\n3. Multiple annotations applied to a field or property can appear on the same line as the corresponding field.\n\\textbf{Valid example}:\n\\begin{lstlisting}[language=Kotlin]\n@MustBeDocumented @CustomAnnotation val loader: DataLoader\n\\end{lstlisting}\n\\subsection*{\\textbf{3.13 Block comments}}\n\\label{sec:3.13}\nBlock comments should be placed at the same indentation level as the surrounding code. See examples below.\n\\textbf{Valid example}:\n\\begin{lstlisting}[language=Kotlin]\nclass SomeClass {\n     /*\n      * This is\n      * okay\n      */\n      fun foo() {}\n}\n\\end{lstlisting}\n\\textbf{Note}: Use \\textbf{/*...*/} block comments to enable automatic formatting by IDEs.\n\\subsection*{\\textbf{3.14 Modifiers and constant values}}\n\\label{sec:3.14}\nThis section contains recommendations regarding modifiers and constant values.\n\\subsubsection*{\\textbf{3.14.1 Declaration with multiple modifiers}}\n\\leavevmode\\newline\n\\label{sec:3.14.1}\nIf a declaration has multiple modifiers, always follow the proper sequence.\n\\textbf{Valid sequence:}\n\\begin{lstlisting}[language=Kotlin]\npublic / internal / protected / private\nexpect / actual\nfinal / open / abstract / sealed / const\nexternal\noverride\nlateinit\ntailrec\ncrossinline\nvararg\nsuspend\ninner\nout\nenum / annotation\ncompanion\ninline / noinline\nreified\ninfix\noperator\ndata\n\\end{lstlisting}\n\\subsubsection*{\\textbf{3.14.2: Separate long numerical values with an underscore}}\n\\leavevmode\\newline\n\\label{sec:3.14.2}\nAn underscore character should separate long numerical values.\n\\textbf{Note:} Using underscores simplifies reading and helps to find errors in numeric constants.\n\\begin{lstlisting}[language=Kotlin]\nval oneMillion = 1_000_000\nval creditCardNumber = 1234_5678_9012_3456L\nval socialSecurityNumber = 999_99_9999L\nval hexBytes = 0xFF_EC_DE_5E\nval bytes = 0b11010010_01101001_10010100_10010010\n\\end{lstlisting}\n\\subsection*{\\textbf{3.15 Strings}}\n\\label{sec:3.15}\nThis section describes the general rules of using strings.\n\\subsubsection*{\\textbf{3.15.1 Concatenation of Strings}}\n\\leavevmode\\newline\n\\label{sec:3.15.1}\nString concatenation is prohibited if the string can fit on one line. Use raw strings and string templates instead. Kotlin has significantly improved the use of Strings:\n\\href{https://kotlinlang.org/docs/reference/basic-types.html#string-templates}{String templates}, \\href{https://kotlinlang.org/docs/reference/basic-types.html#string-literals}{Raw strings}.\nTherefore, compared to using explicit concatenation, code looks much better when proper Kotlin strings are used for short lines, and you do not need to split them with newline characters.\n\\textbf{Invalid example}:\n\\begin{lstlisting}[language=Kotlin]\nval myStr = \"Super string\"\nval value = myStr + \" concatenated\"\n\\end{lstlisting}\n\\textbf{Valid example}:\n\\begin{lstlisting}[language=Kotlin]\nval myStr = \"Super string\"\nval value = \"$myStr concatenated\"\n\\end{lstlisting}\n\\subsubsection*{\\textbf{3.15.2 String template format}}\n\\leavevmode\\newline\n\\label{sec:3.15.2}\n\\textbf{Redundant curly braces in string templates}\nIf there is only one variable in a string template, there is no need to use such a template. Use this variable directly.\n\\textbf{Invalid example}:\n\\begin{lstlisting}[language=Kotlin]\nval someString = \"${myArgument} ${myArgument.foo()}\"\n\\end{lstlisting}\n\\textbf{Valid example}:\n\\begin{lstlisting}[language=Kotlin]\nval someString = \"$myArgument ${myArgument.foo()}\"\n\\end{lstlisting}\n\\textbf{Redundant string template}\nIn case a string template contains only one variable - there is no need to use the string template. Use this variable directly.\n\\textbf{Invalid example}:\n\\begin{lstlisting}[language=Kotlin]\nval someString = \"$myArgument\"\n\\end{lstlisting}\n\\textbf{Valid example}:\n\\begin{lstlisting}[language=Kotlin]\nval someString = myArgument\n\\end{lstlisting}\n\\section*{\\textbf{4. Variables and types}}\n\\label{sec:4.}\nThis section is dedicated to the rules and recommendations for using variables and types in your code.\n\\subsection*{\\textbf{4.1 Variables}}\n\\label{sec:4.1}\nThe rules of using variables are explained in the below topics.\n\\subsubsection*{\\textbf{4.1.1 Do not use Float and Double types when accurate calculations are needed}}\n\\leavevmode\\newline\n\\label{sec:4.1.1}\nFloating-point numbers provide a good approximation over a wide range of values, but they cannot produce accurate results in some cases.\nBinary floating-point numbers are unsuitable for precise calculations because it is impossible to represent 0.1 or any other negative power of 10 in a \\textbf{binary representation} with a finite length.\nThe following code example seems to be obvious:\n\\begin{lstlisting}[language=Kotlin]\n    val myValue = 2.0 - 1.1\n    println(myValue)\n\\end{lstlisting}\nHowever, it will print the following value: \\textbf{0.8999999999999999}\nTherefore, for precise calculations (for example, in finance or exact sciences), using such types as \\textbf{Int}, \\textbf{Long}, \\textbf{BigDecimal}are recommended.\nThe \\textbf{BigDecimal} type should serve as a good choice.\n\\textbf{Invalid example}:\nFloat values containing more than six or seven decimal numbers will be rounded.\n\\begin{lstlisting}[language=Kotlin]\n val eFloat = 2.7182818284f // Float, will be rounded to 2.7182817\n\\end{lstlisting}\n\\textbf{Valid example}: (when precise calculations are needed):\n\\begin{lstlisting}[language=Kotlin]\n    val income = BigDecimal(\"2.0\")\n    val expense = BigDecimal(\"1.1\")\n    println(income.subtract(expense)) // you will obtain 0.9 here\n\\end{lstlisting}\n\\subsubsection*{\\textbf{4.1.2: Comparing numeric float type values}}\n\\leavevmode\\newline\n\\label{sec:4.1.2}\nNumeric float type values should not be directly compared with the equality operator (==) or other methods, such as \\textbf{compareTo()} and \\textbf{equals()}. Since floating-point numbers involve precision problems in computer representation, it is better to use \\textbf{BigDecimal} as recommended in [Rule 4.1.1] to make accurate computations and comparisons. The following code describes these problems.\n\\textbf{Invalid example}:\n\\begin{lstlisting}[language=Kotlin]\nval f1 = 1.0f - 0.9f\nval f2 = 0.9f - 0.8f\nif (f1 == f2) {\n    println(\"Expected to enter here\")\n} else {\n    println(\"But this block will be reached\")\n}\nval flt1 = f1;\nval flt2 = f2;\nif (flt1.equals(flt2)) {\n    println(\"Expected to enter here\")\n} else {\n    println(\"But this block will be reached\")\n}\n\\end{lstlisting}\n\\textbf{Valid example}:\n\\begin{lstlisting}[language=Kotlin]\nval foo = 1.03f\nval bar = 0.42f\nif (abs(foo - bar) > 1e-6f) {\n    println(\"Ok\")\n} else {\n    println(\"Not\")\n}\n\\end{lstlisting}\n\\subsubsection*{\\textbf{4.1.3 Try to use 'val' instead of 'var' for variable declaration}}\n\\leavevmode\\newline\n\\label{sec:4.1.3}\nVariables with the \\textbf{val} modifier are immutable (read-only).\nUsing \\textbf{val} variables instead of \\textbf{var} variables increases code robustness and readability.\nThis is because \\textbf{var} variables can be reassigned several times in the business logic.\nHowever, in some scenarios with loops or accumulators, only \\textbf{var}s are permitted.\n\\subsection*{\\textbf{4.2 Types}}\n\\label{sec:4.2}\nThis section provides recommendations for using types.\n\\subsubsection*{\\textbf{4.2.1: Use Contracts and smart cast as much as possible}}\n\\leavevmode\\newline\n\\label{sec:4.2.1}\nThe Kotlin compiler has introduced \\href{https://kotlinlang.org/docs/reference/typecasts.html#smart-casts}{Smart Casts} that help reduce the size of code.\n\\textbf{Invalid example}:\n\\begin{lstlisting}[language=Kotlin]\n    if (x is String) {\n        print((x as String).length) // x was already automatically cast to String - no need to use 'as' keyword here\n    }\n\\end{lstlisting}\n\\textbf{Valid example}:\n\\begin{lstlisting}[language=Kotlin]\n    if (x is String) {\n        print(x.length) // x was already automatically cast to String - no need to use 'as' keyword here\n    }\n\\end{lstlisting}\nAlso, Kotlin 1.3 introduced \\href{https://kotlinlang.org/docs/reference/whatsnew13.html#contracts}{Contracts} that provide enhanced logic for smart-cast.\nContracts are used and are very stable in \\textbf{stdlib}, for example:\n\n\\begin{lstlisting}[language=Kotlin]\nfun bar(x: String?) {\n    if (!x.isNullOrEmpty()) {\n        println(\"length of '$x' is ${x.length}\") // smartcasted to not-null\n    }\n}\n\\end{lstlisting}\nSmart cast and contracts are a better choice because they reduce boilerplate code and features forced type conversion.\n\\textbf{Invalid example}:\n\\begin{lstlisting}[language=Kotlin]\nfun String?.isNotNull(): Boolean = this != null\nfun foo(s: String?) {\n    if (s.isNotNull()) s!!.length // No smartcast here and !! operator is used\n}\n\\end{lstlisting}\n\\textbf{Valid example}:\n\\begin{lstlisting}[language=Kotlin]\nfun foo(s: String?) {\n    if (s.isNotNull()) s.length // We have used a method with contract from stdlib that helped compiler to execute smart cast\n}\n\\end{lstlisting}\n\\subsubsection*{\\textbf{4.2.2: Try to use type alias to represent types making code more readable}}\n\\leavevmode\\newline\n\\label{sec:4.2.2}\nType aliases provide alternative names for existing types.\nIf the type name is too long, you can replace it with a shorter name, which helps to shorten long generic types.\nFor example, code looks much more readable if you introduce a \\textbf{typealias} instead of a long chain of nested generic types.\nWe recommend using a \\textbf{typealias} if the type contains \\textbf{more than two} nested generic types and is longer than \\textbf{25 chars}.\n\\textbf{Invalid example}:\n\\begin{lstlisting}[language=Kotlin]\nval b: MutableMap<String, MutableList<String>>\n\\end{lstlisting}\n\\textbf{Valid example}:\n\\begin{lstlisting}[language=Kotlin]\ntypealias FileTable = MutableMap<String, MutableList<String>>\nval b: FileTable\n\\end{lstlisting}\nYou can also provide additional aliases for function (lambda-like) types:\n\\begin{lstlisting}[language=Kotlin]\ntypealias MyHandler = (Int, String, Any) -> Unit\ntypealias Predicate<T> = (T) -> Boolean\n\\end{lstlisting}\n\\subsection*{\\textbf{4.3 Null safety and variable declarations}}\n\\label{sec:4.3}\nKotlin is declared as a null-safe programming language. However, to achieve compatibility with Java, it still supports nullable types.\n\\subsubsection*{\\textbf{4.3.1: Avoid declaring variables with nullable types}}\n\\leavevmode\\newline\n\\label{sec:4.3.1}\nTo avoid \\textbf{NullPointerException} and help the compiler prevent Null Pointer Exceptions, avoid using nullable types (with \\textbf{?} symbol).\n\\textbf{Invalid example}:\n\\begin{lstlisting}[language=Kotlin]\nval a: Int? = 0\n\\end{lstlisting}\n\\textbf{Valid example}:\n\\begin{lstlisting}[language=Kotlin]\nval a: Int = 0\n\\end{lstlisting}\nNevertheless, when using Java libraries extensively, you have to use nullable types and enrich the code with \\textbf{!!} and \\textbf{?} symbols.\nAvoid using nullable types for Kotlin stdlib (declared in \\href{https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.collections/}{official documentation}).\nTry to use initializers for empty collections. For example, if you want to initialize a list instead of \\textbf{null}, use \\textbf{emptyList()}.\n\\textbf{Invalid example}:\n\\begin{lstlisting}[language=Kotlin]\nval a: List<Int>? = null\n\\end{lstlisting}\n\\textbf{Valid example}:\n\\begin{lstlisting}[language=Kotlin]\nval a: List<Int> = emptyList()\n\\end{lstlisting}\n\\subsubsection*{\\textbf{4.3.2: Variables of generic types should have an explicit type declaration}}\n\\leavevmode\\newline\n\\label{sec:4.3.2}\nLike in Java, classes in Kotlin may have type parameters. To create an instance of such a class, we typically need to provide type arguments:\n\\begin{lstlisting}[language=Kotlin]\nval myVariable: Map<Int, String> = emptyMap<Int, String>()\n\\end{lstlisting}\nHowever, the compiler can inherit type parameters from the r-value (value assigned to a variable). Therefore, it will not force users to declare the type explicitly.\nThese declarations are not recommended because programmers would need to find the return value and understand the variable type by looking at the method.\n\\textbf{Invalid example}:\n\\begin{lstlisting}[language=Kotlin]\nval myVariable = emptyMap<Int, String>()\n\\end{lstlisting}\n\\textbf{Valid example}:\n\\begin{lstlisting}[language=Kotlin]\nval myVariable: Map<Int, String> = emptyMap()\n\\end{lstlisting}\n\\subsubsection*{\\textbf{4.3.3 Null-safety}}\n\\leavevmode\\newline\n\\label{sec:4.3.3}\nTry to avoid explicit null checks (explicit comparison with \\textbf{null})\nKotlin is declared as \\href{https://kotlinlang.org/docs/reference/null-safety.html}{Null-safe} language.\nHowever, Kotlin architects wanted Kotlin to be fully compatible with Java; that's why the \\textbf{null} keyword was also introduced in Kotlin.\nThere are several code-structures that can be used in Kotlin to avoid null-checks. For example: \\textbf{?:},  \\textbf{.let \\{\\}}, \\textbf{.also \\{\\}}, e.t.c\n\\textbf{Invalid example:}\n\\begin{lstlisting}[language=Kotlin]\n// example 1\nvar myVar: Int? = null\nif (myVar == null) {\n    println(\"null\")\n    return\n}\n// example 2\nif (myVar != null) {\n    println(\"not null\")\n    return\n}\n// example 3\nval anotherVal = if (myVar != null) {\n                     println(\"not null\")\n                     1\n                 } else {\n                     2\n                 }\n// example 4\nif (myVar == null) {\n    println(\"null\")\n} else {\n    println(\"not null\")\n}\n\\end{lstlisting}\n\\textbf{Valid example:}\n\\begin{lstlisting}[language=Kotlin]\n// example 1\nvar myVar: Int? = null\nmyVar?: run {\n    println(\"null\")\n    return\n}\n// example 2\nmyVar?.let {\n    println(\"not null\")\n    return\n}\n// example 3\nval anotherVal = myVar?.also {\n                     println(\"not null\")\n                     1\n                 } ?: 2\n// example 4\nmyVar?.let {\n    println(\"not null\")\n} ?: run { println(\"null\") }\n\\end{lstlisting}\n\\textbf{Exceptions:}\nIn the case of complex expressions, such as multiple \\textbf{else-if} structures or long conditional statements, there is common sense to use explicit comparison with \\textbf{null}.\n\\textbf{Valid examples:}\n\\begin{lstlisting}[language=Kotlin]\nif (myVar != null) {\n    println(\"not null\")\n} else if (anotherCondition) {\n    println(\"Other condition\")\n}\n\\end{lstlisting}\n\\begin{lstlisting}[language=Kotlin]\nif (myVar == null || otherValue == 5 && isValid) {}\n\\end{lstlisting}\nPlease also note, that instead of using \\textbf{require(a != null)} with a not null check - you should use a special Kotlin function called \\textbf{requireNotNull(a)}.\n\\section*{\\textbf{5. Functions}}\n\\label{sec:5.}\nThis section describes the rules of using functions in your code.\n\\subsection*{\\textbf{5.1 Function design}}\n\\label{sec:5.1}\nDevelopers can write clean code by gaining knowledge of how to build design patterns and avoid code smells.\nYou should utilize this approach, along with functional style, when writing Kotlin code.\nThe concepts behind functional style are as follows:\nFunctions are the smallest unit of combinable and reusable code.\nThey should have clean logic, \\textbf{high cohesion}, and \\textbf{low coupling} to organize the code effectively.\nThe code in functions should be simple and not conceal the author's original intentions.\nAdditionally, it should have a clean abstraction, and control statements should be used straightforwardly.\nThe side effects (code that does not affect a function's return value but affects global/object instance variables) should not be used for state changes of an object.\nThe only exceptions to this are state machines.\nKotlin is \\href{https://www.slideshare.net/abreslav/whos-more-functional-kotlin-groovy-scala-or-java}{designed} to support and encourage functional programming, featuring the corresponding built-in mechanisms.\nAlso, it supports standard collections and sequences feature methods that enable functional programming (for example, \\textbf{apply}, \\textbf{with}, \\textbf{let}, and \\textbf{run}), Kotlin Higher-Order functions, function types, lambdas, and default function arguments.\nAs [previously discussed], Kotlin supports and encourages the use of immutable types, which in turn motivates programmers to write pure functions that avoid side effects and have a corresponding output for specific input.\nThe pipeline data flow for the pure function comprises a functional paradigm. It is easy to implement concurrent programming when you have chains of function calls, where each step features the following characteristics:\n2.\tVerifiability\n3.\tTestability\n4.\tReplaceability\n5.\tPluggability\n6.\tExtensibility\n7.\tImmutable results\nThere can be only one side effect in this data stream, which can be placed only at the end of the execution queue.\n\\subsubsection*{\\textbf{5.1.1 Avoid functions that are too long}}\n\\leavevmode\\newline\n\\label{sec:5.1.1}\nThe function should be displayable on one screen and only implement one certain logic.\nIf a function is too long, it often means complex and could be split or simplified. Functions should consist of 30 lines (non-empty and non-comment) in total.\n\\textbf{Exception:} Some functions that implement complex algorithms may exceed 30 lines due to aggregation and comprehensiveness.\nLinter warnings for such functions \\textbf{can be suppressed}.\nEven if a long function works well, new problems or bugs may appear due to the function's complex logic once it is modified by someone else.\nTherefore, it is recommended to split such functions into several separate and shorter functions that are easier to manage.\nThis approach will enable other programmers to read and modify the code properly.\n\\subsubsection*{\\textbf{5.1.2 Avoid deep nesting of function code blocks}}\n\\leavevmode\\newline\n\\label{sec:5.1.2}\nThe nesting depth of a function's code block is the depth of mutual inclusion between the code control blocks in the function (for example: if, for, while, and when).\nEach nesting level will increase the amount of effort needed to read the code because you need to remember the current \"stack\" (for example, entering conditional statements and loops).\n\\textbf{Exception:} The nesting levels of the lambda expressions, local classes, and anonymous classes in functions are calculated based on the innermost function. The nesting levels of enclosing methods are not accumulated.\nFunctional decomposition should be implemented to avoid confusion for the developer who reads the code.\nThis will help the reader switch between contexts.\n\\subsubsection*{\\textbf{5.1.3 Avoid using nested functions}}\n\\leavevmode\\newline\n\\label{sec:5.1.3}\nNested functions create a more complex function context, thereby confusing readers.\nWith nested functions, the visibility context may not be evident to the code reader.\n\\textbf{Invalid example}:\n\\begin{lstlisting}[language=Kotlin]\nfun foo() {\n    fun nested():String {\n        return \"String from nested function\"\n    }\n    println(\"Nested Output: ${nested()}\")\n}\n\\end{lstlisting}\n\\subsubsection*{\\textbf{5.1.4 Negated function calls}}\n\\leavevmode\\newline\n\\label{sec:5.1.4}\nDon't use negated function calls if it can be replaced with negated version of this function\n\\textbf{Invalid example}:\n\\begin{lstlisting}[language=Kotlin]\nfun foo() {\n    val list = listOf(1, 2, 3)\n\n    if (!list.isEmpty()) {\n        // Some cool logic\n    }\n}\n\\end{lstlisting}\n\\textbf{Valid example}:\n\\begin{lstlisting}[language=Kotlin]\nfun foo() {\n    val list = listOf(1, 2, 3)\n\n    if (list.isNotEmpty()) {\n        // Some cool logic\n    }\n}\n\\end{lstlisting}\n\\subsection*{\\textbf{5.2 Function arguments}}\n\\label{sec:5.2}\nThe rules for using function arguments are described in the below topics.\n\\subsubsection*{\\textbf{5.2.1 The lambda parameter of the function should be placed at the end of the argument list}}\n\\leavevmode\\newline\n\\label{sec:5.2.1}\nWith such notation, it is easier to use curly brackets, leading to better code readability.\n\\textbf{Valid example}:\n\\begin{lstlisting}[language=Kotlin]\n// declaration\nfun myFoo(someArg: Int, myLambda: () -> Unit) {\n// ...\n}\n// usage\nmyFoo(1) {\nprintln(\"hey\")\n}\n\\end{lstlisting}\n\\subsubsection*{\\textbf{5.2.2 Number of function parameters should be limited to five}}\n\\leavevmode\\newline\n\\label{sec:5.2.2}\nA long argument list is a \\href{https://en.wikipedia.org/wiki/Code\\_smell}{code smell} that leads to less reliable code.\nIt is recommended to reduce the number of parameters. Having \\textbf{more than five} parameters leads to difficulties in maintenance and conflicts merging.\nIf parameter groups appear in different functions multiple times, these parameters are closely related and can be encapsulated into a single Data Class.\nIt is recommended that you use Data Classes and Maps to unify these function arguments.\n\\subsubsection*{\\textbf{5.2.3 Use default values for function arguments instead of overloading them}}\n\\leavevmode\\newline\n\\label{sec:5.2.3}\nIn Java, default values for function arguments are prohibited. That is why the function should be overloaded when you need to create a function with fewer arguments.\nIn Kotlin, you can use default arguments instead.\n\\textbf{Invalid example}:\n\\begin{lstlisting}[language=Kotlin]\nprivate fun foo(arg: Int) {\n    // ...\n}\nprivate fun foo() {\n    // ...\n}\n\\end{lstlisting}\n\\textbf{Valid example}:\n\\begin{lstlisting}[language=Kotlin]\n private fun foo(arg: Int = 0) {\n     // ...\n }\n\\end{lstlisting}\n\\subsubsection*{\\textbf{5.2.4 Synchronizing code inside asynchronous code}}\n\\leavevmode\\newline\n\\label{sec:5.2.4}\nTry to avoid using \\textbf{runBlocking} in asynchronous code\n\\textbf{Invalid example}:\n\\begin{lstlisting}[language=Kotlin]\nGlobalScope.async {\n    runBlocking {\n        count++\n    }\n}\n\\end{lstlisting}\n\\subsubsection*{\\textbf{5.2.5 Long lambdas should have explicit parameters}}\n\\leavevmode\\newline\n\\label{sec:5.2.5}\nThe lambda without parameters shouldn't be too long.\nIf a lambda is too long, it can confuse the user. Lambda without parameters should consist of 10 lines (non-empty and non-comment) in total.\n\\subsubsection*{\\textbf{5.2.6 Avoid using unnecessary}}\n\\leavevmode\\newline\n\\label{sec:5.2.6}\nExpressions with unnecessary, custom labels generally increase complexity and worsen the maintainability of the code.\n\\textbf{Invalid example}:\n\\begin{lstlisting}[language=Kotlin]\nrun lab@ {\n    list.forEach {\n        return@lab\n    }\n}\n\\end{lstlisting}\n\\textbf{Valid example}:\n\\begin{lstlisting}[language=Kotlin]\nlist.forEachIndexed { index, i ->\n    return@forEachIndexed\n}\nlab@ for(i: Int in q) {\n    for (j: Int in q) {\n        println(i)\n        break@lab\n    }\n}\n\\end{lstlisting}\n\\section*{\\textbf{6. Classes}}\n\\label{sec:6.}\n\\subsection*{\\textbf{6.1 Classes}}\n\\label{sec:6.1}\nThis section describes the rules of denoting classes in your code.\n\\subsubsection*{\\textbf{6.1.1  Denoting a class with a single constructor}}\n\\leavevmode\\newline\n\\label{sec:6.1.1}\nWhen a class has a single constructor, it should be defined as a primary constructor in the declaration of the class. If the class contains only one explicit constructor, it should be converted to a primary constructor.\n\\textbf{Invalid example}:\n\\begin{lstlisting}[language=Kotlin]\nclass Test {\n    var a: Int\n    constructor(a: Int) {\n        this.a = a\n    }\n}\n\\end{lstlisting}\n\\textbf{Valid example}:\n\\begin{lstlisting}[language=Kotlin]\nclass Test(var a: Int) {\n    // ...\n}\n// in case of any annotations or modifiers used on a constructor:\nclass Test private constructor(var a: Int) {\n    // ...\n}\n\\end{lstlisting}\n\\subsubsection*{\\textbf{6.1.2 Prefer data classes instead of classes without any functional logic}}\n\\leavevmode\\newline\n\\label{sec:6.1.2}\nSome people say that the data class is a code smell. However, if you need to use it (which makes your code more simple), you can utilize the Kotlin \\textbf{data class}. The main purpose of this class is to hold data,\nbut also \\textbf{data class} will automatically generate several useful methods:\n- equals()/hashCode() pair;\n- toString()\n- componentN() functions corresponding to the properties in their order of declaration;\n- copy() function\nTherefore, instead of using \\textbf{normal} classes:\n\\begin{lstlisting}[language=Kotlin]\nclass Test {\n    var a: Int = 0\n        get() = field\n        set(value: Int) { field = value}\n}\nclass Test {\n    var a: Int = 0\n    var b: Int = 0\n\n    constructor(a:Int, b: Int) {\n        this.a = a\n        this.b = b\n    }\n}\n// or\nclass Test(var a: Int = 0, var b: Int = 0)\n\n// or\nclass Test() {\n    var a: Int = 0\n    var b: Int = 0\n}\n\\end{lstlisting}\n\\textbf{prefer data classes:}\n\\begin{lstlisting}[language=Kotlin]\ndata class Test1(var a: Int = 0, var b: Int = 0)\n\\end{lstlisting}\n\\textbf{Exception 1}: Note that data classes cannot be abstract, open, sealed, or inner; that is why these types of classes cannot be changed to a data class.\n\\textbf{Exception 2}: No need to convert a class to a data class if this class extends some other class or implements an interface.\n\\subsubsection*{\\textbf{6.1.3 Do not use the primary constructor if it is empty or useless}}\n\\leavevmode\\newline\n\\label{sec:6.1.3}\nThe primary constructor is a part of the class header; it is placed after the class name and type parameters (optional) but can be omitted if it is not used.\n\\textbf{Invalid example}:\n\\begin{lstlisting}[language=Kotlin]\n// simple case that does not need a primary constructor\nclass Test() {\n    var a: Int = 0\n    var b: Int = 0\n}\n// empty primary constructor is not needed here\n// it can be replaced with a primary contructor with one argument or removed\nclass Test() {\n    var a  = \"Property\"\n    init {\n        println(\"some init\")\n    }\n    constructor(a: String): this() {\n        this.a = a\n    }\n}\n\\end{lstlisting}\n\\textbf{Valid example}:\n\\begin{lstlisting}[language=Kotlin]\n// the good example here is a data class; this example also shows that you should get rid of braces for the primary constructor\nclass Test {\n    var a: Int = 0\n    var b: Int = 0\n}\n\\end{lstlisting}\n\\subsubsection*{\\textbf{6.1.4 Do not use redundant init blocks in your class}}\n\\leavevmode\\newline\n\\label{sec:6.1.4}\nSeveral init blocks are redundant and generally should not be used in your class. The primary constructor cannot contain any code. That is why Kotlin has introduced \\textbf{init} blocks.\nThese blocks store the code to be run during the class initialization.\nKotlin allows writing multiple initialization blocks executed in the same order as they appear in the class body.\nEven when you follow (rule 3.2)[\\#r3.2], this makes your code less readable as the programmer needs to keep in mind all init blocks and trace the execution of the code.\nTherefore, you should try to use a single \\textbf{init} block to reduce the code's complexity. If you need to do some logging or make some calculations before the class property assignment, you can use powerful functional programming. This will reduce the possibility of the error if your \\textbf{init} blocks' order is accidentally changed and\nmake the code logic more coupled. It is always enough to use one \\textbf{init} block to implement your idea in Kotlin.\n\\textbf{Invalid example}:\n\\begin{lstlisting}[language=Kotlin]\nclass YourClass(var name: String) {\n    init {\n        println(\"First initializer block that prints ${name}\")\n    }\n\n    val property = \"Property: ${name.length}\".also(::println)\n\n    init {\n        println(\"Second initializer block that prints ${name.length}\")\n    }\n}\n\\end{lstlisting}\n\\textbf{Valid example}:\n\\begin{lstlisting}[language=Kotlin]\nclass YourClass(var name: String) {\n    init {\n        println(\"First initializer block that prints ${name}\")\n    }\n    val property = \"Property: ${name.length}\".also { prop ->\n        println(prop)\n        println(\"Second initializer block that prints ${name.length}\")\n    }\n}\n\\end{lstlisting}\nThe \\textbf{init} block was not added to Kotlin to help you initialize your properties; it is needed for more complex tasks.\nTherefore if the \\textbf{init} block contains only assignments of variables - move it directly to properties to be correctly initialized near the declaration.\nIn some cases, this rule can be in clash with [6.1.1], but that should not stop you.\n\\textbf{Invalid example}:\n\\begin{lstlisting}[language=Kotlin]\nclass A(baseUrl: String) {\n    private val customUrl: String\n    init {\n        customUrl = \"$baseUrl/myUrl\"\n    }\n}\n\\end{lstlisting}\n\\textbf{Valid example}:\n\\begin{lstlisting}[language=Kotlin]\nclass A(baseUrl: String) {\n    private val customUrl = \"$baseUrl/myUrl\"\n}\n\\end{lstlisting}\n\\subsubsection*{\\textbf{6.1.5 Explicit supertype qualification}}\n\\leavevmode\\newline\n\\label{sec:6.1.5}\nThe explicit supertype qualification should not be used if there is no clash between called methods. This rule is applicable to both interfaces and classes.\n\\textbf{Invalid example}:\n\\begin{lstlisting}[language=Kotlin]\nopen class Rectangle {\n    open fun draw() { /* ... */ }\n}\nclass Square() : Rectangle() {\n    override fun draw() {\n        super<Rectangle>.draw() // no need in super<Rectangle> here\n    }\n}\n\\end{lstlisting}\n\\subsubsection*{\\textbf{6.1.6 Abstract class should have at least one abstract method}}\n\\leavevmode\\newline\n\\label{sec:6.1.6}\nAbstract classes are used to force a developer to implement some of its parts in their inheritors.\nWhen the abstract class has no abstract methods, it was set \\textbf{abstract} incorrectly and can be converted to a regular class.\n\\textbf{Invalid example}:\n\\begin{lstlisting}[language=Kotlin]\nabstract class NotAbstract {\n    fun foo() {}\n\n    fun test() {}\n}\n\\end{lstlisting}\n\\textbf{Valid example}:\n\\begin{lstlisting}[language=Kotlin]\nabstract class NotAbstract {\n    abstract fun foo()\n\n    fun test() {}\n}\n// OR\nclass NotAbstract {\n    fun foo() {}\n\n    fun test() {}\n}\n\\end{lstlisting}\n\\subsubsection*{\\textbf{6.1.7 When using the}}\n\\leavevmode\\newline\n\\label{sec:6.1.7}\nKotlin has a mechanism of \\href{https://kotlinlang.org/docs/reference/properties.html#backing-properties}{backing properties}.\nIn some cases, implicit backing is not enough and it should be done explicitly:\n\\begin{lstlisting}[language=Kotlin]\nprivate var _table: Map<String, Int>? = null\nval table: Map<String, Int>\n    get() {\n        if (_table == null) {\n            _table = HashMap() // Type parameters are inferred\n        }\n        return _table ?: throw AssertionError(\"Set to null by another thread\")\n    }\n\\end{lstlisting}\nIn this case, the name of the backing property (\\textbf{\\_table}) should be the same as the name of the real property (\\textbf{table}) but should have an underscore (\\textbf{\\_}) prefix.\nIt is one of the exceptions from the [identifier names rule]\n\\subsubsection*{\\textbf{6.1.8 Avoid using custom getters and setters}}\n\\leavevmode\\newline\n\\label{sec:6.1.8}\nKotlin has a perfect mechanism of \\href{https://kotlinlang.org/docs/reference/properties.html#properties-and-fields}{properties}.\nKotlin compiler automatically generates \\textbf{get} and \\textbf{set} methods for properties and can override them.\n\\textbf{Invalid example:}\n\\begin{lstlisting}[language=Kotlin]\nclass A {\n    var size: Int = 0\n        set(value) {\n            println(\"Side effect\")\n            field = value\n        }\n        // user of this class does not expect calling A.size receive size * 2\n        get() = field * 2\n}\n\\end{lstlisting}\nFrom the callee code, these methods look like access to this property: \\textbf{A().isEmpty = true} for setter and \\textbf{A().isEmpty} for getter.\nHowever, when \\textbf{get} and \\textbf{set} are overridden, it  isn't very clear for a developer who uses this particular class.\nThe developer expects to get the property value but receives some unknown value and some extra side-effect hidden by the custom getter/setter.\nUse extra functions instead to avoid confusion.\n\\textbf{Valid example}:\n\\begin{lstlisting}[language=Kotlin]\nclass A {\n    var size: Int = 0\n    fun initSize(value: Int) {\n        // some custom logic\n    }\n\n    // this will not confuse developer and he will get exactly what he expects\n    fun goodNameThatDescribesThisGetter() = this.size * 2\n}\n\\end{lstlisting}\n\\textbf{Exception:} \\textbf{Private setters} are only exceptions that are not prohibited by this rule.\n\\subsubsection*{\\textbf{6.1.9 Never use the name of a variable in the custom getter or setter}}\n\\leavevmode\\newline\n\\label{sec:6.1.9}\nIf you ignored [recommendation 6.1.8], be careful with using the name of the property in your custom getter/setter\nas it can accidentally cause a recursive call and a \\textbf{StackOverflow Error}. Use the \\textbf{field} keyword instead.\n\\textbf{Invalid example (very bad)}:\n\\begin{lstlisting}[language=Kotlin]\nvar isEmpty: Boolean\n    set(value) {\n        println(\"Side effect\")\n        isEmpty = value\n    }\n    get() = isEmpty\n\\end{lstlisting}\n\\subsubsection*{\\textbf{6.1.10 No trivial getters and setters are allowed in the code}}\n\\leavevmode\\newline\n\\label{sec:6.1.10}\nIn Java, trivial getters - are the getters that are just returning the field value.\nTrivial setters - are merely setting the field with a value without any transformation.\nHowever, in Kotlin, trivial getters/setters are generated by default. There is no need to use it explicitly for all types of data structures in Kotlin.\n\\textbf{Invalid example}:\n\\begin{lstlisting}[language=Kotlin]\nclass A {\n    var a: Int = 0\n    get() = field\n    set(value: Int) { field = value }\n    //\n}\n\\end{lstlisting}\n\\textbf{Valid example}:\n\\begin{lstlisting}[language=Kotlin]\nclass A {\n    var a: Int = 0\n    get() = field\n    set(value: Int) { field = value }\n    //\n}\n\\end{lstlisting}\n\\subsubsection*{\\textbf{6.1.11 Use 'apply' for grouping object initialization}}\n\\leavevmode\\newline\n\\label{sec:6.1.11}\nIn Java, before functional programming became popular, many classes from common libraries used the configuration paradigm.\nTo use these classes, you had to create an object with the constructor with 0-2 arguments and set the fields needed to run the object.\nIn Kotlin, to reduce the number of dummy code line and to group objects \\href{https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/apply.html}{apply extension} was added:\n\n\\textbf{Invalid example}:\n\\begin{lstlisting}[language=Kotlin]\nclass HttpClient(var name: String) {\n    var url: String = \"\"\n    var port: String = \"\"\n    var timeout = 0\n\n    fun doRequest() {}\n}\nfun main() {\n    val httpClient = HttpClient(\"myConnection\")\n    httpClient.url = \"http://example.com\"\n    httpClient.port = \"8080\"\n    httpClient.timeout = 100\n\n    httpCLient.doRequest()\n}\n\\end{lstlisting}\n\\textbf{Valid example}:\n\\begin{lstlisting}[language=Kotlin]\nclass HttpClient(var name: String) {\n    var url: String = \"\"\n    var port: String = \"\"\n    var timeout = 0\n    fun doRequest() {}\n}\nfun main() {\n    val httpClient = HttpClient(\"myConnection\")\n            .apply {\n                url = \"http://example.com\"\n                port = \"8080\"\n                timeout = 100\n            }\n    httpClient.doRequest()\n}\n\\end{lstlisting}\n\\subsubsection*{\\textbf{6.1.12 Prefer Inline classes when a class has a single property}}\n\\leavevmode\\newline\n\\label{sec:6.1.12}\nIf a class has only one immutable property, then it can be converted to the inline class.\nSometimes it is necessary for business logic to create a wrapper around some type. However, it introduces runtime overhead due to additional heap allocations. Moreover, if the wrapped type is primitive, the performance hit is terrible, because primitive types are usually heavily optimized by the runtime, while their wrappers don't get any special treatment.\n\\textbf{Invalid example}:\n\\begin{lstlisting}[language=Kotlin]\nclass Password {\n    val value: String\n}\n\\end{lstlisting}\n\\textbf{Valid example}:\n\\begin{lstlisting}[language=Kotlin]\ninline class Password(val value: String)\n\\end{lstlisting}\n\\subsection*{\\textbf{6.2 Extension functions}}\n\\label{sec:6.2}\nThis section describes the rules of using extension functions in your code.\n\\href{https://kotlinlang.org/docs/reference/extensions.html}{Extension functions} is a killer-feature in Kotlin.\nIt gives you a chance to extend classes that were already implemented in external libraries and helps you to make classes less heavy.\nExtension functions are resolved statically.\n\\subsubsection*{\\textbf{6.2.1 Use extension functions for making logic of classes less coupled}}\n\\leavevmode\\newline\n\\label{sec:6.2.1}\nIt is recommended that for classes, the non-tightly coupled functions, which are rarely used in the class, should be implemented as extension functions where possible.\nThey should be implemented in the same class/file where they are used. This is a non-deterministic rule, so the code cannot be checked or fixed automatically by a static analyzer.\n\\subsubsection*{\\textbf{6.2.2 No extension functions with the same name and signature if they extend base and inheritor classes}}\n\\leavevmode\\newline\n\\label{sec:6.2.2}\nYou should have ho extension functions with the same name and signature if they extend base and inheritor classes (possible\\_bug).esolved statically. There could be a situation when a developer implements two extension functions: one is for the base class and another for the inheritor.\nThis can lead to an issue when an incorrect method is used.\n\\textbf{Invalid example}:\n\\begin{lstlisting}[language=Kotlin]\nopen class A\nclass B: A()\n// two extension functions with the same signature\nfun A.foo() = \"A\"\nfun B.foo() = \"B\"\nfun printClassName(s: A) { println(s.foo()) }\n// this call will run foo() method from the base class A, but\n// programmer can expect to run foo() from the class inheritor B\nfun main() { printClassName(B()) }\n\\end{lstlisting}\n\\subsubsection*{\\textbf{6.2.3 Don't use extension functions for the class in the same file}}\n\\leavevmode\\newline\n\\label{sec:6.2.3}\nYou should not use extension functions for the class in the same file, where it is defined.\n\\textbf{Invalid example}:\n\\begin{lstlisting}[language=Kotlin]\nclass SomeClass {\n\n}\nfun SomeClass.deleteAllSpaces() {\n\n}\n\\end{lstlisting}\n\\subsection*{\\textbf{6.3 Interfaces}}\n\\label{sec:6.3}\nAn \\textbf{Interface} in Kotlin can contain declarations of abstract methods, as well as method implementations. What makes them different from abstract classes is that interfaces cannot store state.\nThey can have properties, but these need to be abstract or to provide accessor implementations.\nKotlin's interfaces can define attributes and functions.\nIn Kotlin and Java, the interface is the main presentation means of application programming interface (API) design and should take precedence over the use of (abstract) classes.\n\\subsection*{\\textbf{6.4 Objects}}\n\\label{sec:6.4}\nThis section describes the rules of using objects in code.\n\\subsubsection*{\\textbf{6.4.1 Instead of using utility classes}}\n\\leavevmode\\newline\n\\label{sec:6.4.1}\nAvoid using utility classes/objects; use extensions instead. As described in [6.2 Extension functions], using extension functions is a powerful method.\nThis enables you to avoid unnecessary complexity and class/object wrapping and use top-level functions instead.\n\\textbf{Invalid example}:\n\\begin{lstlisting}[language=Kotlin]\nobject StringUtil {\n    fun stringInfo(myString: String): Int {\n        return myString.count{ \"something\".contains(it) }\n    }\n}\nStringUtil.stringInfo(\"myStr\")\n\\end{lstlisting}\n\\textbf{Valid example}:\n\\begin{lstlisting}[language=Kotlin]\nfun String.stringInfo(): Int {\n    return this.count{ \"something\".contains(it) }\n}\n\"myStr\".stringInfo()\n\\end{lstlisting}\n\\subsubsection*{\\textbf{6.4.2 Objects should be used for Stateless Interfaces}}\n\\leavevmode\\newline\n\\label{sec:6.4.2}\nKotlin’s objects are extremely useful when you need to implement some interface from an external library that does not have any state.\nThere is no need to use classes for such structures.\n\\textbf{Valid example}:\n\\begin{lstlisting}[language=Kotlin]\ninterface I {\n    fun foo()\n}\nobject O: I {\n    override fun foo() {}\n}\n\\end{lstlisting}\n\\subsubsection*{\\textbf{6.5.1 kts files should wrap logic into top-level scope}}\n\\leavevmode\\newline\n\\label{sec:6.5.1}\nIt is still recommended wrapping logic inside functions and avoid using top-level statements for function calls or wrapping blocks of code\nin top-level scope functions like \\textbf{run}.\n\\textbf{Valid example}:\n\\begin{lstlisting}[language=Kotlin]\nrun {\n    // some code\n}\nfun foo() {\n}\n\\end{lstlisting}\n"
  },
  {
    "path": "wp/sections/compare.tex",
    "content": "\\subsection{About ktlint}\nKtlint is a popular an anti-bikeshedding Kotlin linter with a built-in formatter created by Pinterest\\footnote{\\url{https://github.com/pinterest/}}. It tries to reflect official code style from \\texttt{kotlinlang.org} and Android Kotlin Style Guide and then automatically apply these rules to your codebase. Ktlint can check and automatically fix code. It claims to be simple and easy to use. As it is focused more on checking code-style and code-smell related issues, ktlint inspections work with Abstract Syntax Tree generated by Kotlin parser. Ktlint framework has some basic utilities to make the work with Kotlin AST easier, but anyway all inspections work with original ASTNode provided by Kotlin parser.\n\nKtlint has been developed since 2016 and since then it has 3.8k stars, 309 forks and 390 closed PRs (2020). It looks to be the most popular and mature linter in the Kotlin community right now with approximately 15k lines of code written.\n\nKtlint has its own set of rules, which are divided on standard and experimental rules. But unfortunately the number of fixers and checkers in the standard ruleset is very few (~20 rules) and inspections are trivial.\n\nKtlint can be used as a plugin for Maven, Gradle or command line app. \\texttt{.editorconfig} file should be modified to configure rules. This is the - only configuration that ktlint provides and it contains just simple configuration like the number of spaces in indents. Actually user even can’t configure specific rules (for example to disable or suppress any of them), instead you can provide some common settings like the number of spaces for indenting. In other words, ktlint has a \"fixed hardcoded” code-style that is not very configurable.\n\nIf you want to implement your own rules you need to create a your own Ruleset. Ktlint is very user-friendly for creation of custom Rulesets. In this case ktlint will parse the code using a Kotlin parser and will trigger your inspection (as visitor) for each node of AST. Ktlint uses javas \\texttt{ServiceLoader} to discover all available Rulesets. \\texttt{ServiceLoader} is used to inject your own implementation of rules for the static analysis. In this case ktlint becomes both a third-party dependency and a framework. Basically you should provide implementation of \\texttt{RuleSetProvider} interface.\n\nKtlint refers to article on Medium\\footnote{\\url{https://medium.com/mydevnotes/ktlint-improve-your-kotlin-code-quality-with-lint-checks-13a4456c4600}} on how to create a custom Ruleset and a Rule.\n\nA lot of projects uses ktlint as their code formatting tool. For example, OmiseGo \\footnote{\\url{https://github.com/omgnetwork/android-sdk}} (currently rebranding to OMG Network) - is a quite popular cryptocurrency.\n\nTo summarize: Ktlint is very mature and useful as a framework for creating your own checker\\&fixer of Kotlin code and doing AST-analysis. It can be very useful if you need only simple inspections that check (and fix) code-style issues (like indents).\n\n\\begin{figure}[H]\n    \\centering\n    \\includegraphics[scale = 0.6]{pictures/ktlint.png}\n    \\caption{Ktlint Code Frequency}\n    \\label{fig:png_ktlint}\n\\end{figure}\n\n\\subsection{About detekt}\nDetekt \\footnote{\\url{https://github.com/detekt/detekt}} is a static code analysis tool. It operates on an abstract syntax tree (AST) and meta-information provided by Kotlin compiler. On the top of that info, it does a complex analysis of the code. However, this project is more focused on checking the code rather than fixing. Similarly, to ktlint, it has its own rules and inspections. Detekt uses wrapped ktlint to redefine RuleSet of ktlint as it’s formatting rules.\n\nDetekt supports detection of code smells, bugs searching and code-style checking. It has a highly configurable rule sets (can even make suppression of issues from the code). And the number of checkers is large: it has more than 100 inspections. Detekt has IntelliJ integration, third-party integrations for Maven, Bazel and Github actions and a mechanism for suppression of their warnings with @Suppress annotation from the code. It is being developed since 2016 and today it has 3.2k stars, 411 forks and 1850 closed PRs. It has about 45k lines of code. And its codebase is the biggest comparing to other analyzers.\nDetekt is used in such projects as fountain \\footnote{\\url{https://github.com/xmartlabs/fountain}} or Kaspresso   \\footnote{\\url{https://github.com/KasperskyLab/Kaspresso}}.\n\nTo summarize: Detekt is very useful as a Kotlin static analyser for CI/CD. It tries to find bugs in the code and is focused more on checking of the code. Detekt has 100+ rules which check the code.\n\n\\begin{figure}[H]\n    \\centering\n    \\includegraphics[scale = 0.6]{pictures/detekt.png}\n    \\caption{Detekt Code Frequency}\n    \\label{fig:png_detekt}\n\\end{figure}\n\n\\subsection{About ktfmt}\nKtfmt formats is a program that formats Kotlin code, based on google-java-format. Its development started in Facebook at the end of 2019. It can be added to client’s project through a Maven dependency, Gradle dependency, IntelliJ plugin or run through a command line. Ktfmt is not a configurable application, so to change any rule logic you need to download the project and redefine some constants. Ktfmt has 214 stars, 16 forks, 20 closed PRs and around 7500 lines of code.\n\nTo summarize: no one knows why Facebook has invested their money in this tool. Nothing new was introduced. If they really needed to have new rules - they could create their own Ruleset for ktlint or detekt.\n\n\\begin{figure}[H]\n    \\centering\n    \\includegraphics[scale = 0.6]{pictures/ktfmt.png}\n    \\caption{Ktfmt Code Frequency}\n    \\label{fig:png_ktfmt}\n\\end{figure}\n\n\\subsection{About diKTat}\nDiktat is a static code analysis tool as well as ktlint and detect. But diktat is not only a tool, but also a coding convention that describes in details all the rules that you should follow when writing a code on Kotlin. Its development has started in 2020 and at the time of writing this article diKTat has 168 stars and 13 forks. DiKTat operates on AST provided by kotlin compiler. So why diKTat is better?\n\nFirst of all, it supports much more rules than ktlint. Its ruleset includes more than 100 rules, that can both check and fix your code.\n\nSecondly, diKTat is configurable. A lot of rules have their own settings, and all of them can be easily understood. For example, you can choose whether you need a copyright, choose a length of line or you can configure your indents.\n\nThird, diKTat is very easy to configure. You don’t need to spend hours only to understand what each rule does. Diktat’s ruleset is a \\texttt{.yml} file, where each rule is commented out with the description. Also you can suppress error on the particular lines of code using \\texttt{@Suppress} annotation in your code.\n\nDiKTat can be used as a CI/CD tool in order to avoid merging errors in the code. Overall it can find code smells and code style issues. Also it can find pretty not obvious bugs by complex AST analysis. Diktat works with maven, gradle and as command-line application powered by ktlint.\n\nTo summarize: diktat contains a strict coding convention that was not yet introduced by other linters. It works both as a checker and as a fixer. Diktat has much more inspections (100+) and is very configurable (each inspection can be disabled/configured separately), so you can configure it for your particular project.\n\n\\begin{figure}[H]\n    \\centering\n    \\includegraphics[scale = 0.6]{pictures/diktat.png}\n    \\caption{DiKTat Code Frequency}\n    \\label{fig:png_diktat}\n\\end{figure}\n\n\\subsection{A few words about Jetbrains}\nJetbrains invented  Kotlin and created one of the best IDEs for Java and Kotlin called IntelliJ. This IDE supports a built-in linter. However, it is not a well-configurable tool, you are not able to specify your own coding convention and it is not useful for CI/CD as it is highly coupled with UI. Unfortunately such static analysis is not so effective as it cannot prevent merging of the code with bugs into the repository. As experience shows - many developers simply ignore those static analysis errors until they are blocked from merging their pull requests. So it is not so suitable for CI/CD, but very good for finding and fixing issues inside your IDE.\n\n\\subsection{Summary}\nTo sum up, four linters, excepting diKTat, were mentioned above and each of them has it's own strengths and weaknesses. Diktat, in its turn, is uniting its strengths and providing new features in code linting and fixing tools.\n\\begin{center}\n\\begin{tabular}{ |p{3cm}|p{2.5cm}|p{2.5cm}|p{2.5cm}|p{2.5cm}| }\n\\hline\n\\multicolumn{5}{|c|}{\\textbf{Comparing table}} \\\\\n\\hline\n& diKTat& ktlint &detekt & ktfmt \\\\\n\\hline\nstarting year & 2020 & 2016 & 2016 & 2019 \\\\\nstars & 168 & 3.2k & 3.8k & 214\\\\ \nforks & 13 & 299 & 411 & 16\\\\\nclosed PRs & 321 & 390 & 1850 & 20 \\\\\nlines of code & 32k & 15k & 45k & 7,5k\\\\\nnumber of rules & $>$100 & $\\approx$ 20 & $>$100 & $\\approx$ 10 \\\\\nis configurable & yes & no & yes/no & no \\\\\nmaven/gradle plugin & both & both & gradle only & no \\\\\nweb version & yes & yes & no & no \\\\\n\\hline\n\n\\hline\n\\end{tabular}\n\\end{center}"
  },
  {
    "path": "wp/sections/conclusion.tex",
    "content": "\\par DiKTat is a static code analyzer that finds and fixes code style inconsistencies. DiKTat is configurable, easy-to-use and it implements CI/CD pipelines, which distinguishes it from analogues. We offer many convenient ways to use diktat in projects, so you can use it as Maven/Gradle plugin, CLI tool, Web or github actions. It supports more than 100 rules, where each of them has clear explanation and can be configured by user. For diktat we have instroduced the coding convention for Kotlin code that now has 6 chapters and will be extended in the future.\n\\par When the development of diKTat will be finished, we are going to support rules, update frameworks and track latest Kotlin releases to keep diKTat up to date. We are also planning to implement some number of Inspections that can detect real bugs in Kotlin code."
  },
  {
    "path": "wp/sections/definition.tex",
    "content": "Before we will move one, it is necessary to define some terms for better understanding of context.\nThe first and basic concept that should be introduced is \\textbf{Rule} (marked with $R_i$). Rule in diKTat is the logic described in a special class named with \\texttt{\"Rule\"} suffix, which checks whether code meets a certain paragraph of code-style. The set - is a well-defined collection of distinct objects, considered as an object in its own right. So we can define a \\textbf{Ruleset} - a set of such code analysis Rules. We will mark any of such set of Rules with $R$.\n\n\\textbf{Inspection} is the part of any Rule. It is an algorithm that can detect (marked with $W_i$) or fix (marked with $F_i$) invalid code. It is very important to understand that $Rule \\neq Inspection (Inspection \\subset Rule)$. We will use $I_i$ notation to mark each separate inspection. So it is obvious that: $I_i = W_i \\cup F_i$, where $i \\in \\mathbb {N}$. Using the same logic we can say that $R = \\bigcup\\limits_{i} R_i$ where $R_i = \\bigcup\\limits_{j} I_j$.\n\n\\textbf{Abstract syntax tree (AST)} is a tree representation of the abstract syntactic structure of source code written in a programming language (Kotlin in our case). Each node of the tree denotes a construct occurring in the source code. \\textbf{CI/CD} - continuous integration (CI) and continuous delivery (CD) is a methodology that allows application development teams to make changes to code more frequently and reliably \\cite{ref:cicd}. \\textbf{KDoc} - is the language used to document Kotlin code (the equivalent of Java's JavaDoc)."
  },
  {
    "path": "wp/sections/diKTat.tex",
    "content": "\\subsection{What is diKTat?}\nDiKTat \\footnote{\\url{https://github.com/saveourtool/diKTat}} - is a formal strict code-style for Kotlin language and a linter with a set of rules that implement this code-style. Basically, it is a collection of Kotlin code style rules implemented as AST visitors on top of KTlint framework \\footnote{\\url{https://github.com/pinterest/ktlint}}. Diktat detects and automatically fixes code style errors and code smells based on the configuration of rules. DiKTat is a highly configurable framework, that can be extended further by adding custom rules. It can be run as command line application or with maven or gradle plugins. In this paper, we will explain how diKTat works, describe its advantages and disadvantages and compare it with other static analyzers for Kotlin. The main idea is to use diktat in your CI/CD pipeline.\n\n\\subsection{Why diKTat?}\nDiKTat permits formal flexible description or Rules and Inspections expressed by means of yml file. We looked at similar existing projects and realized that their functionality does not give us a chance to implement our own configurable code style. Most of rules which we wanted to implement were missing in other analyzers. Mostly all of those analyzers had hardcoded logic and prohibited configuration. That’s why we decided that we need to create convenient, user friendly and easily configured tool for developers.\n\nFirst of all, diKTat has its own highly configurable Ruleset $R_{diktat}$ that contains unique Inspections, missing in other Kotlin static analyzers. You just need to set your own options which fit your project the most. In case you don't want to do this - you can use the default configuration, but some of complex inspections will be disabled. Basically, Ruleset is an \\texttt{yml} file with a description of each rule.\n\nSecondly, DiKTat has its own plugins and can be run via Maven, Gradle and command line. Developer can use build automation system that he prefers.\n\nFinally, developer can disable with diKTat each inspection from the code using special annotations on the line where he wants to suppress an Inspection."
  },
  {
    "path": "wp/sections/download.tex",
    "content": "\\subsection{CLI-application}\nYou can run diKTat as a CLI-application. To do this you simply need to install ktlint/diktat and to run it via console with a special option \\texttt{--disabled\\_rules=standard} that we have introduced in ktlint \\footnote{\\url{https://github.com/pinterest/ktlint/pull/977/files}} :\n\n\\begin{center}\n\\texttt{\\$ ./ktlint -R diktat.jar --disabled\\_rules=standard \"path/to/project/**/*.kt\"}\n\\end{center}\n\nAfter the run, all detected errors will displayed. Each warning contains of a rule name, a description of the rule and line/column where this error appears in the code. It also will contain \\texttt{\"cannot be auto-corrected\"} note if the Inspection does not have autofixer. The format of warning is the following:\n\n\\begin{center}\n/path/to/project/file.kt:6:5: [WARNING\\_ID\\_NAME] free text of the warning (cannot be auto-corrected)\n\\end{center}\n\nPlease also note, that as diktat is using ktlint framework - the format of the reported warnings can be changed: it can be xml, json and other formats that are supported by ktlint. Please refer to ktlint documentation \\footnote{\\url{https://github.com/pinterest/ktlint\\#creating-a-reporter}} to see the information about custom reporters.\n\n\\subsection{Maven plugin}\nMaven plugin was introduced for diktat since the version 0.1.3. The following code snippet from \\texttt{pom.xml} shows how to use diktat with Maven plugin:\n\\begin{lstlisting}[caption={DiKTat with Maven plugin}, label={lst:maven}, language=Kotlin]\n          <plugin>\n                <groupId>com.saveourtool.diktat</groupId>\n                <artifactId>diktat-maven-plugin</artifactId>\n                <version>${diktat.version}</version>\n                <executions>\n                    <execution>\n                        <id>diktat</id>\n                        <phase>none</phase>\n                        <goals>\n                            <goal>check</goal>\n                            <goal>fix</goal>\n                        </goals>\n                        <configuration>\n                            <inputs>\n                                <input>${project.basedir}/src/main/kotlin</input>\n                                <input>${project.basedir}/src/test/kotlin</input>\n                            </inputs>\n                            <diktatConfigFile>diktat-analysis.yml</diktatConfigFile>\n                            <excludes>\n                               <exclude>${project.basedir}/src/test/kotlin/excluded</exclude>\n                            </excludes>\n                        </configuration>\n                    </execution>\n                </executions>\n            </plugin>\n\\end{lstlisting}\n\nTo run diktat in only-check mode use the command: \\texttt{mvn diktat:check@diktat}. To run diktat in autocorrect mode use the command: \\texttt{mvn diktat:fix@diktat}.\n\n\n\\subsection{Gradle plugin}\nThis plugin is available since version 0.1.5. The following code snippet shows how to configure Gradle plugin for diktat.\n\n\\begin{lstlisting}[caption={DiKTat with Gradle plugin}, label={lst:gradle1}, language=Kotlin]\nplugins {\n    id(\"com.saveourtool.diktat.diktat-gradle-plugin\") version \"0.1.7\"\n}\n\\end{lstlisting}\n\nOr use buildscript syntax:\n\n\\begin{lstlisting}[caption={DiKTat with Gradle plugin}, label={lst:gradle1}, language=Kotlin]\n\nbuildscript {\n    repositories {\n        mavenCentral()\n    }\n    dependencies {\n        classpath(\"com.saveourtool.diktat:diktat-gradle-plugin:0.1.7\")\n    }\n}\napply(plugin = \"com.saveourtool.diktat.diktat-gradle-plugin\")\n\\end{lstlisting}\n\nThen you can configure diktat using diktat extension:\n\n\\begin{lstlisting}[caption={DiKTat extension}, label={lst:gradle2}, language=Kotlin]\ndiktat {\n    inputs = files(\"src/**/*.kt\")  // file collection that will be checked by diktat\n    debug = true  // turn on debug logging\n    excludes = files(\"src/test/kotlin/excluded\")  // these files will not be checked by diktat\n}\n\\end{lstlisting}\n\nYou can run diktat checks using task \\texttt{diktatCheck} and automatically fix errors with tasks \\texttt{diktatFix}.\n\n\\subsection{Configuratifon file}\nAs described above, diKTat has a configuration file. Note that you should place the \\textsl{diktat-analysis.yml} file containing the diktat configuration in the parent directory of your project when running as a CLI application. Diktat-maven-plugin and diktat-gradle-plugin have a separate option to setup the path where the configuration file is stored.\n\n\\subsection{DiKTat-web}\nThe easiest way to use diktat without any downloads or installations is the web version of the app. You can try it by the following link: \\url{https://ktlint-demo.herokuapp.com/demo}. Web app supports both checking and fixing, using either ktlint or diktat ruleset. For diktat you can also upload a custom configuration file.\n"
  },
  {
    "path": "wp/sections/feature.tex",
    "content": "\\par As described above, diKTat is configurable and user-friendly. But these are not all of it's advantages and features. Below we will present and describe unusual and important killer-features of diKTat.\n\n\\subsection{Configuration file}\n\\par\nIt's worth starting with the configuration file. This is a file in which the user can manually turn rules on and off or configure the rules settings. Below is one of the rules in the configuration file.\n\\\\\n\\begin{lstlisting}[ caption={Part of configuration file.},\nlabel={lst:example1}, language=yaml]\n- name: DIKTAT_COMMON\n  configuration:\n    # put your package name here - it will be autofixed and checked\n    domainName: your.name.here\n- name: COMMENTED_OUT_CODE\n  enabled: true\n- name: HEADER_MISSING_OR_WRONG_COPYRIGHT\n  enabled: true\n  configuration:\n    isCopyrightMandatory: true\n    copyrightText: 'Copyright (c) Your Company Name Here. 2010-2020'\n    testDirs: test\n- name: FILE_IS_TOO_LONG\n  enabled: true\n  configuration:\n    maxSize: '2000'\n    ignoreFolders: ' '\n\\end{lstlisting}\nEach Inspection in this file has 3 fields: \\texttt{name} - the name of the Inspection, \\texttt{enabled} - whether the rule is enabled or disabled (all rules are enabled by default), \\texttt{configuration} - parameters for the Inspection. With the first two, everything is obvious. The third parameter is less obvious. The configuration is a set of \"properties\" to configure this rule. For example, for an Inspection \\texttt{FILE\\underline{ }IS\\underline{ }TOO\\underline{ }LONG}, that checks the number of lines in a Kotlin file, the user can configure the maximum number of lines allowed in the file - by changing the \"maxSize\" in the configuration, or the user can specify paths to folders that do not need to be checked - by writing the path in \"ignoreFolders\". \\\\\n\n\\subsection{Create ASTNode}\nAnother feature is a special mechanism that allows you to construct an abstract syntax tree node from the text. It is extremely useful for creating automatic fixers, because you do not need to think about the AST implementation and you simply need to provide a text block with a code. Everything will be done under the hood by the framework. This algorithm can parse the code even partially, when you do not need to save the hierarchy of the file (with imports/packages/classes).\nFor example it can parse and provide you a sub-tree for these lines of code:\n\n\\begin{lstlisting}[caption={Example of creating an AST from text of code.}, label={lst:example1}, language=Kotlin]\n\tval nodeFromText: ASTNode = KotlinParser().createNode(\"val age: Int = 21\")\n\\end{lstlisting}\n\n\\tikzstyle{every node}=[draw=black,thick,anchor=west, scale = 0.5]\n\n\\begin{tikzpicture}[%\n  grow via three points={one child at (0.3,-0.8) and\n  two children at (0.3,-0.8) and (0.3,-1.5)},\n  scale=0.5,\n  edge from parent path={(\\tikzparentnode.south) |- (\\tikzchildnode.west)}]\n\n  \\node {PROPERTY}\n    child { node {val}}\n    child {node {WHITE\\underline{ }SPACE}}\n    child {node {IDENTIFIER}}\n    child {node {COLON}}\n    child {node {WHITE\\underline{ }SPACE}}\n    child {node {TYPE\\underline{ }REFERENCE}\n    \tchild {node {USER\\underline{ }TYPE}\n\t\tchild {node {REFERENCE\\underline{ }EXPRESSION}\n\t\t\tchild {node {IDENTIFIER}}\n\t\t}\n\t}\n    }\n    child [missing] {}\n    child [missing] {}\n    child [missing] {}\n    child {node {WHITE\\underline{ }SPACE}}\n    child {node {EQ}}\n    child {node {WHITE\\underline{ }SPACE}}\n    child {node {INTEGER\\underline{ }CONSTANT}\n    \tchild {node {INTEGER\\underline{ }LIRETAL}}\n    };\n\\end{tikzpicture}\n\\\\\n\nAs you can see in the example, we pass the text of the source code, that we want to transform, to the method.  What's going on inside this method? First of all, special system properties (used by Kotlin parser) are set (for example: set \"idea.io.use.nio2\" to true). If the text of the code contains high-level keywords like \\texttt{import} or \\texttt{package}, then the method builds a tree with a root node of the FILE type, otherwise it tries with a different root type. In both cases, at the end, if the tree contains a node with type \\texttt{ERROR\\underline{ }ELEMENT}, it means that some of the code and the method was unable to build the tree and, therefore, throws an exception.\\\\\nThis helps us to implement such complex inspections like the detection of commented code (and distinguish real comments from commented code blocks), helps easily fix the code without manually building sub-trees in visitors.\\\\\n\n\\subsection{Suppress annotation}\n\\par\nWhat if the user wants one of the diKTat Inspections not to check a particular piece of code? The \\textsl{SUPPRESS} annotation will help us with it. This annotation can be used to ignore a certain Inspection in a certain code block. For instance, if we run this code:\n\n\\begin{lstlisting}[caption={Function with incorrect name.}, label={lst:example1}, language=Kotlin]\n/**\n * This is example\n */\n\npackage com.saveourtool.diktat\n\n/**\n * Simple class\n */\nclass User(private val name: String, private val age: Int) {\n\t/**\n\t * Function with incorrect name\n\t *\n\t * @return is username longer than age\n\t */\n\tfun IsInCoRrEcTnAMe() = name.length > age\n}\n\n\\end{lstlisting}\n\nDiktat will raise the warning:\n$$\n\\texttt{ \\small{ $\\big[$FUNCTION\\underline{ }NAME\\underline{ }INCORRECT\\underline{ }CASE$\\big]$  function/method name should be in lowerCamelCase}}\n$$\n\nBut if there is a \\texttt{@Suppress} before this method, then there will be no warnings during the run:\n\\begin{lstlisting}[caption={Function with incorrect name, but with suppressed Inspection.}, label={lst:example1}, language=Kotlin]\n/**\n * This is example\n */\n\npackage com.saveourtool.diktat\n\n/**\n * Simple class\n */\n@Suppress(\"FUNCTION_NAME_INCORRECT_CASE\")\nclass User(private val name: String, private val age: Int) {\n\t/**\n\t * Function with incorrect name\n\t *\n\t * @return is username longer than age\n\t */\n\tfun IsInCoRrEcTnAMe() = name.length > age\n}\n\n\\end{lstlisting}\n\nThe example shows that the method has a suppress annotation. Therefore, the \\texttt{FUNCTION\\underline{ }NAME\\underline{ }INCORRECT\\underline{ }CASE} rule will be ignored on this method and there will be no error. The search method for a given annotation goes up recursively to the root element of type \\texttt{FILE}, looking for the annotation. This means that \\texttt{@Suppress} can be placed not only in front of knowingly incorrect code, but also at the upper levels of the abstract syntax tree. In our example, the annotation is not in front of the method, but in front of the class and it still works. Also, you can put several annotations:\n\\begin{lstlisting}[caption={Several suppression annotations}, label={lst:example1}, language=Kotlin]\n@set:[Suppress(\"WRONG_DECLARATION_ORDER\") Suppress(\"IDENTIFIER_LENGTH\")]\n\\end{lstlisting}\n\n\\subsection{WEB}\nIt worth mentioning that there is a web version of diKTat. This is a handy tool that can be used quickly without any installations, and it is very simple. The link can be found in or you can find it in \"\\nameref{sec:download}\" chapter or in ktlint project as reference.\\footnote{\\url{https://github.com/pinterest/ktlint\\#online-demo}}\n\\begin{figure}[H]\n  \\centering\n  \\includegraphics[scale=0.3]{pictures/web-example.png}\n  \\caption{Diktat-web online demo}\n\\end{figure}\n\n\\subsection{Options validation}\nAs it has been mention earlier, diktat has a highly customizable configuration file, but manually editing it is error-prone, for example, name of the rule can be incorrect due to a typo. Diktat will validate configuration file on startup and suggest the closest name based on \\textsl{Levenshtein} method.\n\n\\subsection{Self checks}\nDiktat fully supports self checking of it's own code using both release and snapshot (master) versions. Diktat uses it's self to validate the code inside during it's CI/CD process.\n"
  },
  {
    "path": "wp/sections/introduction.tex",
    "content": "It is necessary to follow a specific style of code during software development. Otherwise code will become less readable and the developer will not be able to  understand other programmers’ intent. It can lead to functional defects and bugs in the code. Static analyzers, in it's turn, have methods for detecting and auto-correcting style errors and bugs. Modern linters and static analyzers are extremely useful not only for simple code-style analysis but also for bugs detection and automatic code fixing.\n\nThere are many methods and techniques used by existing analyzers to ﬁnd bugs (path-sensitive data ﬂow analysis \\cite{ref:kremenek}, alias analysis \\cite{ref:effective}, type analysis \\cite{ref:simple}, symbolic execution \\cite{ref:dis}, abstract interpretation \\cite{ref:dis}).\n\nSenior developer can write the same comment again and again in hundreds of code reviews. Static analysis reduces this bureaucracy as it can be thought of as an automated code review process, because it can detect those issues in code automatically. And of course it perfectly reduces the human factor in the review process. There are two main tasks that can be solved by static code analysis: identifying errors (bugs) in programs and recommending code formatting (fixes). This means that the analyzer allows you, for example, to check whether the source code complies with the accepted coding convention and automatically fix found issues. Also, a static analyzer can be used to determine the level of maintainability of a code. It shows how easy is it to read, modify and adapt a given code of software by detecting code-smells and design patterns used in the code. Static analysis tools allow you to identify a large number of errors in the design phase, which significantly reduces the development cost of the entire project. Static analysis covers the entire code - it checks even those code fragments that are difficult to test. It does not depend on the compiler used and the environment in which the compiled program will be executed.\n\nThis white-paper covers the work that was done to create a static analyzer for Kotlin language, called diKTat. It also briefly describes it's implementation and functionality. You can treat this document as a \"how-to\" instruction for diKTat."
  },
  {
    "path": "wp/sections/kotlin.tex",
    "content": "This section explains why we are focused exactly on the static analysis for Kotlin language.\n\nKotlin is a cross-platform, statically typed, general-purpose programming language with type inference. Kotlin is designed to interoperate fully with Java, and the JVM version of Kotlin's standard library depends on the Java Class Library, but type inference allows its syntax to be more concise. This language can be called \"Java on steroids\" as it takes best features from different languages and puts it on the top of JVM-world. Kotlin mainly targets the JVM, but also is compiled to JavaScript (e.g. for frontend web applications using React or Thymeleaf) or native code (via LLVM), e.g. for native iOS apps sharing business logic with Android apps. % wikipedia\n\nKotlin has quickly skyrocketed in popularity. It's used by Google, Square, Pinterest, Pivotal, Netflix, Atlassian and many other companies. It's the fastest-growing programming language, according to GitHub, growing over 2,5 times in the past year (2019). It was voted one of the five most loved languages, according to Stack Overflow. There are even meetups and conferences focused only on Kotlin\\footnote{\\url{https://www.businessinsider.com/kotlin-programming-language-explained-popularity-2019-5\\#:\\~:text=Kotlin\\%20has\\%20quickly\\%20skyrocketed\\%20in,times\\%20in\\%20the\\%20past\\%20year}}.\n% https://www.businessinsider.com/kotlin-programming-language-explained-popularity-2019-5#:~:text=Kotlin%20has%20quickly%20skyrocketed%20in,times%20in%20the%20past%20year\n\nKotlin is used in a lot of ways. For example, it can be used for backend development using \\texttt{ktor} framework (Kotlin framework developed by JetBrains), and  \\texttt{Spring} framework that also has first-party support for kotlin (\\texttt{Spring} is one of the most popular framework on Java for Web development). Kotlin/JS provides the ability to transpile your Kotlin code to JavaScript, as well as providing JS variant of Kotlin standard library and interopability with existing JS dependencies, both for Node.js and browser. There are numerous ways how Kotlin/JS can be used. For instance, Kotlin/JS is used to create frontend web applications, server-side and serverless applications, libraries for use with JavaScript and TypeScript.\n\nSupport for multiplatform programming is one of key benefits. It reduces time for writing and maintaining the same code for different platforms while retaining the flexibility and benefits of native programming. We think that it is the main reason why Kotlin is so popular in the community of mobile developers.\n\nKotlin supports well asynchronous or non-blocking programming. Whether we're creating server-side, desktop or mobile applications, it's important that we provide an experience that is not only fluid from the user's perspective, but scalable when needed. Kotlin has chosen a very flexible approach one by providing Coroutine support as a first-party library  \\texttt{kotlinx.coroutines} with a kotlin compiler plugin. A coroutine is a concurrent design pattern that you can use on Android to simplify code that executes asynchronously. Coroutines (in a form of kotlinx.coroutines library and kotlin compiler plugin) were added to Kotlin in version 1.3 and are based on established concepts from other languages. Also, coroutines do not only open the doors to an easy asynchronous programming in Kotlin, but also provide a wealth of other possibilities such as concurrency, actors, etc.\n\nOn Android, coroutines help to manage long-running tasks that might otherwise block the main thread and cause your app to become unresponsive. Over 50\\% of professional developers who use coroutines have reported that productivity had increased. So designers of Kotlin made a correct decision. Coroutines help you to write cleaner and more concise code for your applications.\n\nThe state of Kotlin in the Q3 of 2020 (according to the latest Kotlin Census and statistical data):\n\\begin{itemize}\n    \\item 4,7 million users\n    \\item 65\\% of users use Kotlin in production\n    \\item Kotlin is primary language for 56\\% of users, which means the main or only\n    one they use at work\n    \\item 100+ people are on the Kotlin development team at JetBrains\n    \\item 350+ independent contributors develop the language and its ecosystem outside\n    of JetBrains\n\\end{itemize}\n\n% https://techcrunch.com/2019/05/07/kotlin-is-now-googles-preferred-language-for-android-app-development/\nKotlin is used by developers of open-source operating systems like HarmonyOS and Android. In 2019 Google announced that the Kotlin programming language is now its preferred language for Android app developers. In the same year Stack Overflow stated that Kotlin is fourth most loved language in community. Nowadays there are over 60\\% of android developers who use Kotlin as their main language. \\footnote{\\url{https://techcrunch.com/2019/05/07/kotlin-is-now-googles-preferred-language-for-android-app-development/}}\n\nKotlin's popularity can be explained by the rising number of Android users (last year, 124.4m in the USA) and, thus, Android-based devices. 80\\% of Kotlin programmers use the language to build Android apps, 31\\% for back-end applications, 30\\% for SDK/libraries.\nKotlin is also interoperable with Java, which allows developers to use all existing Android libraries in a Kotlin app. Now (2020) Kotlin is in the top-10 of PYPL rating:\n\n\\begin{figure}[H]\n    \\centering\n    \\includegraphics[scale = 0.3]{pictures/kotlinRating.png}\n    \\caption{Top programming languages, 2020}\n    \\label{fig:top_languages}\n\\end{figure}\n\nOverall, Kotlin is a modern language that gains its popularity incredibly fast. It is mostly used by Android developers, but other \"branches of programming\" are gaining popularity as well, for example Spring framework (the most popular Java framework) supports Kotlin. It supports both OO (object-oriented) and FP (function-oriented) programming paradigms. Since the release 1.4 Kotlin claims to bring major updates every 6 month."
  },
  {
    "path": "wp/sections/work.tex",
    "content": "Diktat does AST-analysis, using Abstract Syntax Tree for creation of internal representation (IR) from the parsed code by the kotlin-compiler. This chapter describes how diktat works.\n\n\\subsection{ktlint}\nTo quickly and efficiently analyze the program code, you first need to transform it into a convenient data structure. This is exactly what ktlint does - it parses plain text code into an abstract syntax tree. So we decided not to choose the way of development that was chosen by Facebook in ktfmt and not invent our own framework for parsing the code. We decided to write our own Ruleset on the top of ktlint framework. The good thing is that we were able to inject our set of rules to ktlint via Java's \\texttt{ServiceLoader}\\footnote{\\url{https://docs.oracle.com/javase/8/docs/api/java/util/ServiceLoader.html}}\n\n In ktlint, the transformation of code happens in the \\textsl{prepareCodeForLinting}\\footnote{\\url{https://github.com/pinterest/ktlint/blob/master/ktlint-core/src/main/kotlin/com/pinterest/ktlint/core/KtLint.kt}} method. This method uses kotlin-compiler-embeddable library to create a root node of type FILE.\nFor example, this simple code:\n\\begin{lstlisting}[caption={Simple function that will be transformed to AST}, label={lst:example1}, language=Kotlin]\n\tfun main() {\n\t\tprintln(\"Hello World\")\n\t}\n\\end{lstlisting}\n\nwill be converted into the following AST:\n\n\\tikzstyle{every node}=[draw=black,thick,anchor=west, scale = 0.6]\n\n\\begin{tikzpicture}[%\n  grow via three points={one child at (0.3,-0.8) and\n  two children at (0.3,-0.8) and (0.3,-1.5)},\n  scale=0.6,\n  edge from parent path={(\\tikzparentnode.south) |- (\\tikzchildnode.west)}]\n\n  \\node {FILE}\n    child { node {PACKAGE\\underline{ }DIRECTIVE}}\n    child { node {IMPORT\\underline{ }LIST}}\n    child { node {FUN}\n        child {node {fun}}\n        child {node {WHITE\\underline{ }SPACE}}\n        child {node {IDENTIFIER}}\n        child {node {VALUE\\underline{ }PARAMETER\\underline{ }LIST}\n            child {node {LPAR}}\n            child {node {RPAR}}\n        }\n        child [missing] {}\n        child [missing] {}\n        child {node {WHITE\\underline{ }SPACE}}\n        child {node {BLOCK}\n            child {node {LBRACE}}\n            child {node {WHITE\\underline{ }SPACE}}\n            child {node {CALL\\underline{ }EXPRESSION}\n                child {node {REFERENCE\\underline{ }EXPRESSION}\n                    child {node {IDENTIFIER}}\n                }\n                child [missing] {}\n                child {node {VALUE\\underline{ }ARGUMENT\\underline{}LIST}\n                    child {node {LPAR}}\n                    child {node {VALUE\\underline{ }ARGUMENT}\n                        child {node {STRING\\underline{ }TEMPLATE}\n                            child {node {OPEN\\underline{ }QUOTE}}\n                            child {node {LITERAL\\underline{ }STRING\\underline{ }TEMPLATE\\underline{ }ENTRY}\n                                child {node {REGULAR\\underline{ }STRING\\underline{ }PART}}\n                            }\n                            child [missing] {}\n                            child {node {CLOSING\\underline{ }QUOTE}}\n                        }\n                    }\n                    child [missing] {}\n                    child [missing] {}\n                    child [missing] {}\n                    child [missing] {}\n                    child [missing] {}\n                    child [missing] {}\n                    child {node {RPAR}}\n                }\n            }\n            child [missing] {}\n            child [missing] {}\n            child [missing] {}\n            child [missing] {}\n            child [missing] {}\n            child [missing] {}\n            child [missing] {}\n            child [missing] {}\n            child [missing] {}\n            child [missing] {}\n            child [missing] {}\n            child [missing] {}\n            child [missing] {}\n            child {node {WHITE\\underline{ }SPACE}}\n            child {node {RBRACE}}\n        }\n    };\n\\end{tikzpicture}\n\\\\\n\nIf there are error elements inside the constructed tree, then the corresponding error is displayed. If the code is valid and parsed without errors, for each rule in the Ruleset, the \\textsl{visit} method is called for the root node itself and its “children” are sequentially passed.\nWhen you run program, you can pass flags to ktlint - one of them is \\texttt{-F}. This flag means that the rule will not only report an error, but will also try to fix it.\n\n\\subsection{DiKTat}\n\nAnother feature of ktlint is that at it's startup you can provide a JAR file with additional ruleset(s), that will be discovered by the \\texttt{ServiceLoader} and then all AST nodes will be passed to these rules. DiKTat uses this approach.\n\nThe only modification Diktat makes to the framework is that it adds a mechanism to disable Inspection from the code using annotations or configuration file. The set of all rules is described in the \\textsl{DiktatRuleSetProvider}\\footnote{\\url{https://github.com/saveourtool/diKTat/blob/v0.1.3/diktat-rules/src/main/kotlin/com/saveourtool/diktat/ruleset/rules/DiktatRuleSetProvider.kt}} class. This class overrides the \\textsl{get()} method of the \\textsl{RuleSetProvider}\\footnote{\\url{https://github.com/pinterest/ktlint/blob/master/ktlint-core/src/main/kotlin/com/pinterest/ktlint/core/RuleSetProvider.kt}} interface, which returns a set of rules to be \"traversed\". But before returning this set Diktat is reading the configuration file where the user has independently configured all the Inspections. If there is no configuration file, then a warning will be displayed and Inspections will use the default configuration file.\nEach rule must implement the \\textsl{visit} method of the abstract Rule class, which describes the logic of the rule. By the way it is a special case of a famous pattern Visitor \\cite{ref:gang}. Implementation example of the simple Rule that contains one Inspections can be found below.\n\n\\begin{lstlisting}[caption={Example of the Rule.}, label={lst:example1}, language=Kotlin]\nclass SingleLineStatementsRule(private val configRules: List<RulesConfig>) : Rule(\"statement\") {\n    private var isFixMode: Boolean = false\n    private lateinit var emitWarn: EmitType\n\n    override fun visit(node: ASTNode,\n                       autoCorrect: Boolean,\n                       emit: EmitType) {\n        emitWarn = emit\n        isFixMode = autoCorrect\n\n        // all the work is done with ASTNode - this is the type, provided by Kotlin compiler\n        node.getChildren(TokenSet.create(SEMICOLON)).forEach {\n            if (!it.isFollowedByNewline()) {\n                // configuration is checked by warning mechanism under the hood\n                // warnings are mapped to proper paragraph of a code standard\n                MORE_THAN_ONE_STATEMENT_PER_LINE.warnAndFix(\n                        configRules,\n                        emitWarn,\n                        isFixMode,\n                        it.extractLineOfText(),\n                        it.startOffset,\n                        it\n                // this lambda provides the logic that will be used to fix the code\n                ) {\n                    if (it.treeParent.elementType == ENUM_ENTRY) {\n                        node.treeParent.addChild(PsiWhiteSpaceImpl(\"\\n\"), node.treeNext)\n                    } else {\n                        if (!it.isBeginByNewline()) {\n                            val nextNode = it.parent(\n                                    { parent -> parent.treeNext != null },\n                                    strict = false\n                            )?.treeNext\n\n                            node.appendNewlineMergingWhiteSpace(nextNode, it)\n                        }\n                        node.removeChild(it)\n                    }\n                }\n            }\n        }\n    }\n}\n\\end{lstlisting}\n\nThe example above describes the Rule that checks that there are no statements separated by a semicolon. The list of configurations is passed to the parameter of this rule so that the error is displayed only when the Rule is enabled (further it will be described how to enable or disable the Rule). The class fields and the \\textsl{visit()} method are described below. The first parameter in method is of \\textsl{ASTNode} type, this type is produced by the Kotlin compiler. It is important to understand that these visitors are called for each and every node of AST that is provided by the compiler. This is not optimal from the perspective of the performance, but makes the code much more readable and isolated.\n\nThen a check occurs: if the code contains a line in which more than one statement per line and this rule is enabled, then the rule will be executed and, depending on the mode in which the user started ktlint, the rule will either simply report an error or fix it. In our case, when an error is found, the method is called to report and fix the error - \\textsl{warnAndFix()}.\n\nAll warnings that contain similar logic (e.g. regarding formatting of function KDocs) are checked in the same Rule. This way we can make small optimisation and check similar parts of AST only once. Whether the Inspection is enabled or disabled is checked inside \\textsl{warn()} or \\textsl{warnAndFix()} methods. The same works for the suppression of Inspections: right before emitting the warning we check whether any of current node's parents has a Suppress annotation. The diagram below describes it's architecture:\n\n\\begin{figure}[H]\n    \\centering\n    \\includegraphics[scale=0.5]{pictures/class.PNG}\n    \\caption{Diktat class diagram}\n    \\label{fig:top_languages}\n\\end{figure}\n\n\n\\subsection{Examples of unique inspections}\n\\par\nAs already described above, DiKTat has more rules than existing analogues, therefore, it will find and fix more errors and shortcomings and, thereby, make the code cleaner and better. To better understand how detailed are checks in Diktat,let's mention a few examples:\n\n\\begin{enumerate}\n    \\item \\textbf{Package.}\nIn DiKTat, there are about 6 Inspections that are checking the package naming. For comparison: detekt has only one rule, where the package name is simply checked by a pattern, in ktlint there are zero inspections.\n    \\item \\textbf{KDoc.}\nKDoc is an important part of good code to make it easier to understand and navigate the program. In DiKTat there are 15 rules on KDoc, in detekt there are only 7. Therefore, DiKTat will make and correct KDoc in more detail and correctly.\n\\end{enumerate}\n\nThere are also many unique Inspections that other analyzers do not have. Here are some of them:\n\n\\begin{enumerate}\n    \\item \\textbf{COMMENTED\\underline{ }OUT\\underline{ }CODE} – This Inspection checks if the code contains commented code blocks.\n    \\item \\textbf{FILE\\underline{ }CONTAINS\\underline{ }ONLY\\underline{ }COMMENTS} – This rule checks file contains not only comments.\n    \\item \\textbf{LOCAL\\underline{ }VARIABLE\\underline{ }EARLY\\underline{ }DECLARATION} – This rule checks that local variables are declared close to the point where they are first used.\n    \\item \\textbf{AVOID\\underline{ }NESTED\\underline{ }FUNCTIONS} - This rule checks for nested functions and warns and fixes if it finds any. An example of changing the tree when this rule is triggered and DiKTat is run with fix mode:\\\\\\\\\n    \\begin{tikzpicture}[%\n  grow via three points={one child at (0.3,-0.8) and\n  two children at (0.3,-0.8) and (0.3,-1.5)},\n  scale=0.5,\n  edge from parent path={(\\tikzparentnode.south) |- (\\tikzchildnode.west)}]\n\n  \\node(a) {...}\n    child { node {FUN}\n        child {node {...}}\n        child {node {BLOCK}\n            child {node {FUN}\n            \tchild{node{...}}\n\t\tchild{node{BLOCK}\n\t\t\tchild{node{...}}\n\t\t}\n            }\n        }\n    };\n\n    \\node(b) [right of=a, xshift=17cm]{...}\n    \tchild { node {FUN}\n        \t\tchild {node {...}}\n        \t\tchild {node {BLOCK}\n          \t\tchild{node{...}}\n\t\t}\n        }\n        child [missing] {}\n\tchild [missing] {}\n         child { node {FUN}\n        \t\tchild {node {...}}\n        \t\tchild {node {BLOCK}\n          \t\tchild{node{...}}\n\t\t}\n        };\n\n    \\draw[-latex,very thick,shorten <=5mm,shorten >=5mm,] ([xshift=5cm,yshift=-3cm]a.north) to ([xshift=-2cm, yshift=-3cm]b.north);\n\\end{tikzpicture}\n\\\\\n    \\item \\textbf{FLOAT\\underline{ }IN\\underline{ }ACCURATE\\underline{ }CALCULATIONS} - Inspection that checks that floating-point numbers are not used for accurate calculations (see the corresponding Rule from the code style to get more information).\n\n    \\item \\textbf{PACKAGE\\underline{ }NAMING} - This Inspection checks that package name is in a proper format and is separated by dots. This inspection is very demonstrative to show how the work with AST is done.\n\n    This inspection receives different nodes and checks them one by one. First it checks their element type (type of the node in AST). When it's element type equals to \\texttt{PACKAGE\\_DIRECTIVE} it gets the file name and collects all nodes with \\texttt{IDENTIFIER} type as it is shown on the following graph:\n\n\n\\begin{center}\n\\begin{tikzpicture}[nodes={draw, circle}, sibling distance=1.5cm, level distance = 1.2cm, minimum size=3.1cm, scale = 1.2, node distance=16cm]\n\\node(main)[text width = 2cm] { PACKAGE DIRECTIVE}\n    child { node(a) [below left] { PACKAGE} }\n    child { node(b)[below] { WHITE SPACE} }\n    child { node(c)[below right, text width=3cm] {  DOT QUALIFIED EXPRESSION}\n        child { node(d)[below left, text width=2.5cm] { REFERENCE EXPRESSION}\n            child { node(e)[below, fill = selectColor] { IDENTIFIER} }\n        }\n        child { node(f)[below] { DOT} }\n        child { node(g)[below right, text width=2.5cm] { REFERENCE EXPRESSION}\n            child { node(h)[below, fill = selectColor] { IDENTIFIER} }\n        }\n    };\n    \\draw[->, line width = 0.5mm] (main) -- (a);\n    \\draw[->, line width = 0.5mm] (main) --(b);\n    \\draw[->, line width = 0.5mm] (main) -- (c);\n    \\draw[->, line width = 0.5mm] (c) -- (d);\n    \\draw[->, line width = 0.5mm] (d) -- (e);\n    \\draw[->, line width = 0.5mm] (c) -- (f);\n    \\draw[->, line width = 0.5mm] (c) -- (g);\n    \\draw[->, line width = 0.5mm] (g)  --(h);\n\n\\end{tikzpicture}\n\\end{center}\n\nIn order to collect  elements with a proper type, Inspection has to do a tree traversal. Tree traversal is done by a special method called \\texttt{findAllNodesWithCondition()} (see Listing 3). This function searches for a node with a given condition (in this case it is when node's type equals to \\texttt{IDENTIFIER}). As a basis it uses DFS (Depth-first search): it goes recursively in depth of the tree and compares types of AST nodes. When it finds necessary node it returns it and the result from it's parent search as a list, otherwise it returns empty list. At the end the Inspection checks the package name based on identifiers and file name.\n\n\n\\begin{lstlisting}[caption={Method for AST traversal}, label={lst:example1}, language=Kotlin]\n/**\n * This method performs tree traversal and returns all nodes which satisfy the condition\n */\nfun ASTNode.findAllNodesWithCondition(condition: (ASTNode) -> Boolean, withSelf: Boolean = true): List<ASTNode> {\n    val result = if (condition(this) && withSelf) mutableListOf(this) else mutableListOf()\n    return result + this.getChildren(null).flatMap {\n        it.findAllNodesWithCondition(condition)\n    }\n}\n\\end{lstlisting}\n\n\\tikzstyle{every node}=[draw=black,thick,anchor=west, scale = 0.5, font = \\large]\n\\end{enumerate}\n"
  },
  {
    "path": "wp/wp.tex",
    "content": "\\documentclass[acmlarge, screen, nonacm]{acmart}\n\\usepackage[utf8]{inputenc}\n\\usepackage{CJKutf8}\n\\usepackage{graphicx}\n\\usepackage{pgf}\n\\usepackage{multicol}\n\\usepackage{setspace}\n\\usepackage{listings}\n\\usepackage{hyperref}\n\\usepackage{float}\n\\usepackage{placeins}\n\\graphicspath{ {./images/} }\n\\usepackage{tikz}\n\\usepackage{verbatim}\n\\usepackage{cleveref}\n\\usepackage{datetime}\n\\usepackage{longtable}\n\n\\crefname{figure}{Figure}{Figures}\n\\usetikzlibrary{trees}\n\\usetikzlibrary{arrows}\n\n\\definecolor{codegreen}{rgb}{0,0.6,0}\n\\definecolor{codegray}{rgb}{0.5,0.5,0.5}\n\\definecolor{codepurple}{rgb}{0.58,0,0.82}\n\\definecolor{backcolour}{rgb}{0.95,0.95,0.92}\n\\definecolor{OrangeRed}{rgb}{1,0.27,0}\n\\definecolor{ForestGreen}{rgb}{0.1334,0.545,0.1334}\n\\definecolor{NavyBlue}{rgb}{0,0.502,0}\n\\definecolor{BurntOrange}{rgb}{0.8,0.3334,0.1334}\n\\definecolor{selectColor}{rgb}{0.686,1,0.592}\n\n\\newcommand\\YAMLcolonstyle{\\color{black}\\mdseries}\n\\newcommand\\YAMLkeystyle{\\color{BurntOrange}\\bfseries}\n\\newcommand\\YAMLvaluestyle{\\color{black}\\mdseries}\n\n\\lstdefinelanguage{yaml}\n{\n  keywords={true,false,null,y,n},\n  keywordstyle=\\color{darkgray}\\bfseries,\n  basicstyle=\\YAMLkeystyle,\n  sensitive=false,\n  comment=[l]{\\#},\n  morecomment=[s]{/*}{*/},\n  commentstyle=\\color{ForestGreen}\\ttfamily,\n  stringstyle=\\YAMLvaluestyle\\ttfamily,\n  moredelim=[l][\\color{orange}]{\\&},\n  moredelim=[l][\\color{magenta}]{*},\n  moredelim=**[il][\\YAMLcolonstyle{:}\\YAMLvaluestyle]{:},\n  morestring=[b]',\n  morestring=[b]\",\n  literate =    {---}{{\\ProcessThreeDashes}}3\n                {>}{{\\textcolor{red}\\textgreater}}1\n                {|}{{\\textcolor{red}\\textbar}}1\n                {\\ -\\ }{{\\mdseries\\ -\\ }}3,\n}\n\n\\lstdefinestyle{mystyle}{\n\tbackgroundcolor=\\color{backcolour},\n\tcommentstyle=\\color{codegreen},\n\tkeywordstyle=\\color{magenta},\n\tnumberstyle=\\tiny\\color{codegray},\n\tstringstyle=\\color{codepurple},\n\tbasicstyle=\\sffamily\\footnotesize,\n\tbreakatwhitespace=false,\n\tbreaklines=true,\n\tcaptionpos=b,\n\tkeepspaces=true,\n\tnumbers=left,\n\tnumbersep=5pt,\n\tshowspaces=false,\n\tshowstringspaces=false,\n\tshowtabs=false,\n\ttabsize=2\n}\n\n\\lstdefinelanguage{Kotlin}{\n  comment=[l]{//},\n  commentstyle={\\color{gray}\\ttfamily},\n  emph={delegate, filter, first, firstOrNull, forEach, lazy, map, mapNotNull, println, return@},\n  emphstyle={\\color{OrangeRed}},\n  identifierstyle=\\color{black},\n  keywords={abstract, actual, as, as?, break, by, class, companion, continue, data, do, dynamic, else, enum, expect, false, final, for, fun, get, if, import, in, interface, internal, is, object, override, package, private, public, return, set, super, suspend, throw, true, try, typealias, val, var, vararg, when, where, while},\n  keywordstyle={\\color{NavyBlue}\\bfseries},\n  morecomment=[s]{/*}{*/},\n  morestring=[b]\",\n  morestring=[s]{\"\"\"*}{*\"\"\"},\n  ndkeywords={@Deprecated, @JvmField, @JvmName, @JvmOverloads, @JvmStatic, @JvmSynthetic, Array, Byte, Double, Float, this, null, Int, Integer, Iterable, Long, Runnable, Short, String, Boolean},\n  ndkeywordstyle={\\color{BurntOrange}\\bfseries},\n  sensitive=true,\n  stringstyle={\\color{ForestGreen}\\ttfamily},\n}\n\n\\lstset{style=mystyle}\n\\settopmatter{printacmref=false}\n\\settopmatter{printfolios=true}\n\\setcopyright{none}\n\\makeatletter\n\\let\\@authorsaddresses\\@empty\n\n\\makeatletter\n\\let\\newdate\\@date\n\n\\settopmatter{printacmref=false}\n\\setcopyright{none}\n\\renewcommand\\footnotetextcopyrightpermission[1]{}\n\\pagestyle{plain}\n\n\\begin{document}\n\\begin{CJK*}{UTF8}{gbsn}\n\n\\title[]{\n  \\includegraphics[width = 150pt, height = 150]{pictures/logo.png}\\\\\n  DiKTat - Kotlin linter\n}\n\n\\author{Andrey Kuleshov}\n\\email{andrewkuleshov7@gmail.com}\n\\affiliation{\n\\institution{Lomonosov Moscow State University}\n\\country{Russia}\n}\n\\author{Petr Trifanov}\n\\email{peter.trifanov@mail.ru}\n\\affiliation{\n\\institution{Lomonosov Moscow State University}\n\\country{Russia}\n}\n\\author{Denis Kumar}\n\\email{qbextted0@gmail.com}\n\\affiliation{\n\\institution{Higher School of Economics}\n\\country{Russia}\n}\n\\author{Alexander Tsay}\n\\email{aktsay6@gmail.com}\n\\affiliation{\n\\institution{Higher School of Economics}\n\\country{Russia}\n}\n\n\\renewcommand{\\shortauthors}{}\n\n\\maketitle\n\n\\section{Introduction}\n\\label{sec:intro}\n\\input{sections/introduction}\n\n\\section{Definition}\n\\label{sec:definition}\n\\input{sections/definition}\n\n\\section{Kotlin}\n\\label{sec:kotlin}\n\\input{sections/kotlin}\n\n\\section{diKTat}\n\\label{sec:diKTat}\n\\input{sections/diKTat}\n\n\\section{Comparative analysis}\n\\label{sec:compare}\n\\input{sections/compare}\n\n\\section{How does diktat work}\n\\label{sec:work}\n\\input{sections/work}\n\n\\section{Killer-Features}\n\\label{sec:feature}\n\\input{sections/feature}\n\n\\section{How to use diKTat}\n\\label{sec:download}\n\\input{sections/download}\n\n\\section{Conclusion \\& Future Work}\n\\label{sec:conclusion}\n\\input{sections/conclusion}\n\n\\newpage\n\\nocite{*}\n\\bibliographystyle{ieeetr}\n\\bibliography{references.bib}\n\n\\newpage\n\\section{Appendix}\n\\label{sec:appendix}\n\\input{sections/appendix}\n\n\\end{CJK*}\n\\end{document}\n"
  }
]