saveourtool / diktat

Strict coding standard for Kotlin and a custom set of rules for detecting code smells, code style issues and bugs
https://diktat.saveourtool.com
MIT License
537 stars 39 forks source link

`WRONG_INDENTATION` continuation indent expected in `if`-expression #1351

Open icemachined opened 2 years ago

icemachined commented 2 years ago

Describe the bug

Expected behavior

there should be no error after idea style applying

Observed behavior

  "level": "error",
          "locations": [
            {
              "physicalLocation": {
                "artifactLocation": {
                  "uri": "diktat-rules\\src\\main\\kotlin\\org\\cqfn\\diktat\\ruleset\\rules\\chapter2\\kdoc\\KdocComments.kt",
                  "uriBaseId": "%SRCROOT%"
                },
                "region": {
                  "startColumn": 1,
                  "startLine": 116
                }
              }
            }
          ],
          "message": {
            "text": "[WRONG_INDENTATION] only spaces are allowed for indentation and each indentation should equal to 4 spaces (tabs are not allowed): expected 12 but was 16"
          },
          "ruleId": "diktat-ruleset:zct-indentation"

Steps to Reproduce

  1. If you apply idea formatting in KdocComments you have the following piece of code

        if (valueParameterNode.parents().none { it.elementType == PRIMARY_CONSTRUCTOR } ||
            !valueParameterNode.hasChildOfType(VAL_KEYWORD) && 
            !valueParameterNode.hasChildOfType(VAR_KEYWORD)
        ) {
            return
        }

    but diktat report error as far as it expect continuation indent in the last line of if expression like this

        if (valueParameterNode.parents().none { it.elementType == PRIMARY_CONSTRUCTOR } ||
            !valueParameterNode.hasChildOfType(VAL_KEYWORD) && 
                !valueParameterNode.hasChildOfType(VAR_KEYWORD)
        ) {
            return
        }
  2. If you apply idea formatting in KdocComments you have the following piece of code with 16 spaces in second line

        val prevComment = if (valueParameterNode.siblings(forward = false)
                .takeWhile { it.elementType != EOL_COMMENT && it.elementType != BLOCK_COMMENT }
                .all { it.elementType == WHITE_SPACE }
        ) {

    but diktat report error as far as it expect 12 spaces instead 16 as below

        val prevComment = if (valueParameterNode.siblings(forward = false)
              .takeWhile { it.elementType != EOL_COMMENT && it.elementType != BLOCK_COMMENT }
              .all { it.elementType == WHITE_SPACE }
        ) {

Environment information

0x6675636b796f75676974687562 commented 2 years ago

Reg. No. 2, from IDEA standpoint, you get a relative indent of 8 (an absolute indent of 16), because IDEA combines a single indent within an if()-statement (CONTINUATION_INDENT_IN_IF_CONDITIONS is false) with a single indent of a chained function call (CONTINUATION_INDENT_FOR_CHAINED_CALLS is false):

val prevComment = if (valueParameterNode.siblings(forward = false)
        .takeWhile { it.elementType != EOL_COMMENT && it.elementType != BLOCK_COMMENT }
        .all { it.elementType == WHITE_SPACE }
) {
    // block body
}

Minimal repro:

if (""
        .isBlank()) {
    // block body
}
while (""
        .isBlank()) {
    // block body
}
do {
    // block body
} while (""
        .isBlank())

This behaviour is documented in this Wiki section.

0x6675636b796f75676974687562 commented 2 years ago

No. 1 is a separate matter. While all these are correctly formatted (IDEA and diKTat behave consistently):

if (true &&
    true &&
    false) {
    return
}

if (true ||
    true ||
    false) {
    return
}

if (true &&
    true ||
    false) {
    return
}

— here's the minimal repro:

if (true ||
    true &&
        false) {
    return
}

Apparently, this is something related to operator priorities (see 3.5 Line length), since adding parentheses around the 1st two booleans immediately "fixes" the issue (and modifies the logic):

if ((true ||
    true) &&
    false) {
    return
}

Another minimal repro:

if (1 +
    2 *
        3 == 7) {
    return
}

And two more, w/o any if()-statements:

val a = true ||
    true &&
        true

val b = 1 +
    2 *
        3

In this latter case, IDEA would disregard any operator priorities and simply use a (continuation) indent of 8.