Skip to content

WRONG_INDENTATION: extendedIndentAfterOperators ignored if lines are wrapped before a binary operator or an infix function #1340

@0x6675636b796f75676974687562

Description

Consider this fragment (originally from #1312 (comment))

systemUiVisibility = (View.SYSTEM_UI_FLAG_LOW_PROFILE
        or View.SYSTEM_UI_FLAG_FULLSCREEN
        or View.SYSTEM_UI_FLAG_LAYOUT_STABLE
        or View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY
        or View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
        or View.SYSTEM_UI_FLAG_HIDE_NAVIGATION)

Here, infix function calls are wrapped before the operator (the infix function), and extendedIndentAfterOperators has no effect (DiKTat always expects a single indent, not a continuation indent).

The workaround (fir version 1.1.0) is to reformat the code as follows (#1312 (comment)):

systemUiVisibility = (View.SYSTEM_UI_FLAG_LOW_PROFILE or
        View.SYSTEM_UI_FLAG_FULLSCREEN or
        View.SYSTEM_UI_FLAG_LAYOUT_STABLE or
        View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY or
        View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION or
        View.SYSTEM_UI_FLAG_HIDE_NAVIGATION)

The expected behaviour is that extendedIndentAfterOperators is honored regardless of whether the code is wrapped before or after a binary operator.

Other examples (the code style assumes extendedIndentAfterOperators is on):

const val FOO = 1

const val BAR = 2

const val BAZ = 4

fun acceptInteger(arg: Int) = Unit

fun main() {
    acceptInteger(FOO or BAR or BAZ or FOO or BAR or BAZ
            or FOO or BAR or BAZ or FOO or BAR or BAZ or FOO or BAR or BAZ
            or FOO or BAR or BAZ)
}
const val TRUE = true

const val FALSE = false

fun acceptBoolean(arg: Boolean) = Unit

fun main() {
    acceptBoolean(TRUE
            || FALSE
            || TRUE)
}
val c = (3
        + 2)
infix fun Int.combineWith(that: Int) = this + that

fun main() {
    val x = (1
            combineWith 2
            combineWith 3
            combineWith 4
            combineWith 5
            combineWith 6)
}

when- and for-statements

The argument of a when-expression:

when (true
        || false) {
    true -> Unit
    else -> Unit
}

The branch condition of a when-expression:

when ("".isEmpty()) {
    (true
            || false) -> Unit
    else -> Unit
}

Infix function calls in a for-loop:

for (i in 6
        downTo 0
        step 2) {
    return
}

Operator function calls in a for-loop:

for (i in 1
        ..42) {
    return
}

More examples

true
        || false

val a = true
        || false

Expressions wrapped in parentheses

Affected by the fix for #1409, see this comment.

(true
        || false)

val a = (true
        || false)

if-conditions (should be controlled by a separate flag)

A slightly modified example from IDEA code style settings (CONTINUATION_INDENT_IN_IF_CONDITIONS is on):

fun foo1(i1: Int, i2: Int, i3: Int): Int {
    if (i2 > 0
            && i3 < 0) {
        return 2
    }
    return 0
}

Minimal repro:

if (true
        || false) {
    return
}

or

while (true
        || false) {
    return
}

Environment information

  • diktat version: 1.1.0
  • build tool (maven/gradle): Maven
  • how is diktat run (CLI, plugin, etc.): mvn diktat:check
  • kotlin version: 1.6.21
  • operating system: Windows 10

Metadata

Metadata

Labels

bugSomething isn't working

Type

No type

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions