Ktlint: Tab indentation breaks KDoc comments

Created on 24 Aug 2020  路  9Comments  路  Source: pinterest/ktlint

Expected Behavior

/**
 * some function
 */
fun someFunction() {
    return Unit
}

Observed Behavior

/**
    * some function
    */
fun someFunction() {
    return Unit
}

Steps to Reproduce

ktlint -F whatever.kt

I'm fairly certain that this is the reason for this behavior, i.e. it adds one of whatever indentation (space or tab) instead of one space. I think it's probably best to ignore both BLOCK_COMMENT and KDOC. There also doesn't seem to be a test for that; I think adding a KDoc comment to this test should suffice.

I already tried fixing it but didn't really get anywhere; I might open a PR in a few days if I manage to fix it.

Your Environment

  • Version of ktlint used: 0.38.0
  • .editorconfig contains indent_style = tab
bug indentation-rule

All 9 comments

Note: This obviously also triggers wrong warnings when linting, i.e. Unexpected space character(s) and Unexpected indentation (0) (should be 1).

I was planning on changing the indentation tests to require a tab and space variant for all the fixtures which would have caught this.

Thanks for trying out tabs!

I can not reproduce the problem as the original code is not submitted. Also I would like to know what indent styling should be used. So based on the expected behaviour I have tried a number of different situations but still could not reproduce the misalignment of the KDoc.

I did however encounter a problem which is partly related. In case the code uses TAB indentation which is to be replaced with SPACE indentation, this is currently only applied to lines which are the wrong indentation level. As a result, the test below fails:

    @Test
    fun `format issue 850`() {
        val code =
            """
            class Foo {
            ${'\t'}/**
            ${'\t'} * some function
            ${'\t'} */
            ${'\t'}fun someFunction() {
            ${'\t'}${'\t'}// The next line is wrongly indented (one level too deep). Only that line is indented again
            ${'\t'}${'\t'}// by replacing the tab indents with the correct amount of spaced. But for all other lines
            ${'\t'}${'\t'}// in the KDoc and function, the indent is not replaced as those line are at the expected
            ${'\t'}${'\t'}// indentation level. That is still a bug to be fixed.
            ${'\t'}${'\t'}${'\t'}return Unit
            ${'\t'}}
            }
            """.trimIndent()
        val expectedCode =
            """
            class Foo {
                /**
                 * some function
                 */
                fun someFunction() {
                    // The next line is wrongly indented (one level too deep). Only that line is indented again
                    // by replacing the tab indents with the correct amount of spaced. But for all other lines
                    // in the KDoc and function, the indent is not replaced as those line are at the expected
                    // indentation level. That is still a bug to be fixed.
                    return Unit
                }
            }
            """.trimIndent()
        assertThat(IndentationRule().format(code)).isEqualTo(expectedCode)
    }

Can you please write a failing test like above for the problem with shows the problem with incorrectly formatted KDoc?

I tested everything just now with ktlint 0.38.0, 0.39.0, and 0.40.0 on macOS. All three behave as described in my bug report.

I'm not sure what you mean with the original code not being submitted.

The files I used are the following (both with trailing newlines):

.editorconfig, SHA-1 74d3c64e142dcffdce4855f45ae179f175299af7:

[*.{kt,kts}]
indent_style = tab

whatever.kt, SHA-1 c1ae5b3fbcb028435dafaf55276912b1ef146f28:

/**
 * some function
 */
fun someFunction() {
    return Unit
}

I noticed some odd behavior with comments in .editorconfig. Consider the following:

[*.{kt,kts}]
indent_style = tab # this should hopefully work in a future version of ktlint

IntelliJ highlighting looks like this:
image
GitHub highlighting looks the same, see above. According to editorconfig.com:

Comments should go on their own lines.

I'm not sure if "should" means same-line comments are illegal or just discouraged.

However, It seems that the same-line comment makes ktlint ignore the entire line.

Oh, I think you meant that there was no file that when formatted should produce the expected behavior. The expected file is the input file, ktlint finds an error where there is none.

Just reproduced the errors in following test. There seem to be multiple problems when converting space indentation to tabs.

    @Test
    fun `format issue 850 to Tab`() {
        val code =
            """
            class Foo {
                /**
                 * The four spaces in the indentation of the entire KDoc, including start and end marker,
                 * should be indented with a single tab.
                 */
                fun someFunction() {
                    // Those line are indented at the proper level. The space indentation should be replaced
                    // with tabs.
                    return Unit
                }
            }
            """.trimIndent()
        val expectedCode =
            """
            class Foo {
            ${'\t'}/**
            ${'\t'}* The four spaces in the indentation of the entire KDoc, including start and end marker,
            ${'\t'}* should be indented with a single tab.
            ${'\t'}*/
            ${'\t'}fun someFunction() {
            ${'\t'}${'\t'}// Those line are indented at the proper level. The space indentation should be replaced
            ${'\t'}${'\t'}// with tabs.
            ${'\t'}${'\t'}return Unit
            ${'\t'}}
            }
            """.trimIndent()
        assertThat(
            IndentationRule()
                .format(
                    code,
                    mapOf("indent_style" to "tab")
                )
        ).isEqualTo(expectedCode)
    }

Comments should go on their own lines.

I'm not sure if "should" means same-line comments are illegal or just discouraged.

However, It seems that the same-line comment makes ktlint ignore the entire line.

I think that the end of line comments are not allowed. Most like the will just be seen as part of the value. So in this case the indent_style is set to tab # this should hopefully work in a future version of ktlint instead of tab.

Take a look at the editorconfig test suite used by ec4j.

Looks like line comments on the same line should be ignored, no?

Take a look at the editorconfig test suite used by ec4j.

Looks like line comments on the same line should be ignored, no?
This example indeed suggests that end of line comments are allowed.

In PropertyType class of ec4j, the indent_style property is defined as:

    public static final PropertyType<IndentStyleValue> indent_style = new LowerCasingPropertyType<>( //
            "indent_style", //
            "set to tab or space to use hard tabs or soft tabs respectively.",
            new PropertyValueParser.EnumValueParser<IndentStyleValue>(IndentStyleValue.class), //
            IndentStyleValue.valueSet() //
    );

    public enum IndentStyleValue {

        space("Space", ' '),

        tab("Tab", '\t');
    // ...
   }

My guess is that, if EOL comments are really removed, this is done too late in the process. Probably the property is ignored as soon as the value is not found in the list of allowed values (IndentStyleValue.valueSet() in above example) if defined.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

chao2zhang picture chao2zhang  路  4Comments

ZakTaccardi picture ZakTaccardi  路  3Comments

jeremymailen picture jeremymailen  路  3Comments

ZakTaccardi picture ZakTaccardi  路  4Comments

impatient picture impatient  路  5Comments