Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Missing option to define length of a "long supertype list" in Class header #875

Closed
gilgoldzweig opened this issue Aug 30, 2020 · 3 comments · Fixed by #2119
Closed

Missing option to define length of a "long supertype list" in Class header #875

gilgoldzweig opened this issue Aug 30, 2020 · 3 comments · Fixed by #2119

Comments

@gilgoldzweig
Copy link

gilgoldzweig commented Aug 30, 2020

Jetbrains Class header formatting coding conventions
They state that:

For multiple interfaces, the superclass constructor call should be located first and then each interface should be located in a different line

and provide a sample

class Person(
    id: Int,
    name: String,
    surname: String
) : Human(id, name),
    KotlinMaker { /*...*/ }

But they also state the following:

For classes with a long supertype list put a line break after the colon and align all supertype names horizontally

With the attached code sample

class MyFavouriteVeryLongClassHolder :
    MyLongHolder<MyFavouriteVeryLongClass>(),
    SomeOtherInterface,
    AndAnotherOne {

    fun foo() { /*...*/ }
}

But they don't mention what is considered a long supertype list and what is not, which means it should be opened for discussion and an option to change that number.
I personally would love to change the number of interfaces.

Another issue is that it's very hard to understand the issue with the current message:

Indentetation: Missing newline after ":"

I think it should have a proper message along the lines of

Long supertype list: Too many interfaces ($num$ / $max$), align all supertype names horizontally.

@nkiesel
Copy link

nkiesel commented Nov 18, 2020

I second this. I do not really know what exactly "too long" is, but I see constructors with 200+ characters in a single line which definitely is violating the style guide.

@paul-dingemans
Copy link
Collaborator

I second this. I do not really know what exactly "too long" is, but I see constructors with 200+ characters in a single line which definitely is violating the style guide.

The max-line-length rule will disallow such constructors if the corresponding .editorconfig property has been set. This issue should be solved as part of the bigger issue #1349.

@paul-dingemans paul-dingemans added this to the 1.0 (Yeah!) milestone Apr 16, 2023
@paul-dingemans paul-dingemans self-assigned this Jul 3, 2023
paul-dingemans added a commit that referenced this issue Jul 9, 2023
…consistent format. In code style `ktlint_official`, super types are always wrapped to a separate line. In other code styles, super types are only wrapped in classes having multiple super types. Especially for code style `ktlint_official` the class headers are rewritten in a more consistent format.

Closes #875
Closes #1349
@paul-dingemans
Copy link
Collaborator

The new class-signature will wrap the super types depending on the code style. For code style ktlint_official the super type will always be wrapped. For the other code styles, wrapping of the super type is done for classes having multiple super types or when exceeding the max_line_length.

Given input below:

class Foo {
    // body
}

class Foo() {
    // body
}

class Foo(val bar1: Bar) {
    // body
}

class Foo(
    val bar1: Bar,
    val bar2: Bar,
) {
    // body
}

class Foo : FooBar("bar") {
    // body
}

class Foo : FooBar("bar1", "bar2") {
    // body
}

class Foo : FooBar(
    "bar1",
    "bar2",
) {
    // body
}

class Foo :
    FooBar(
        "bar1",
        "bar2",
    ) {
    // body
}

class Foo(val bar1: Bar) : FooBar(bar1) {
    // body
}

class Foo(
    val bar1: Bar,
    val bar2: Bar,
) : FooBar(bar1) {
    // body
}

class Foo(
    val bar1: Bar,
    val bar2: Bar,
) : FooBar(bar1, bar2) {
    // body
}

class Foo(
    val bar1: Bar,
    val bar2: Bar,
) : FooBar(
    bar1,
    bar2,
) {
    // body
}

class Foo(
    val bar1: Bar,
    val bar2: Bar,
) : FooBar(
    bar1,
    bar2,
) {
    // body
}

class Foo : FooBar("bar"), BarFoo1, BarFoo2 {
    // body
}

class Foo : FooBar("bar1", "bar2"), BarFoo1, BarFoo2 {
    // body
}

class Foo : FooBar(
    "bar1",
    "bar2"
), BarFoo1, BarFoo2 {
    // body
}

class Foo : FooBar(
    "bar1",
    "bar2"
),
    BarFoo1,
    BarFoo2 {
    // body
}

class Foo :
    FooBar(
        "bar1",
        "bar2",
    ),
    BarFoo1,
    BarFoo2 {
    // body
}

class Foo(
    val bar1: Bar,
    val bar2: Bar,
) : FooBar(bar1, bar2),
    BarFoo1,
    BarFoo2 {
    // body
}

class Foo(
    val bar1: Bar,
    val bar2: Bar,
) : FooBar(
    bar1,
    bar2,
),
    BarFoo1,
    BarFoo2 {
    // body
}

class Foo(
    val bar1: Bar,
    val bar2: Bar,
) : FooBar(
    bar1,
    bar2,
),
    BarFoo1,
    BarFoo2 {
    // body
}

class Foo
    constructor(
        val bar1: Bar,
        val bar2: Bar,
    ) : FooBar(bar1, bar2),
        BarFoo1,
        BarFoo2 {
    // body
}

will be formatted in ktlint_official as:

class Foo {
    // body
}

class Foo {
    // body
}

class Foo(
    val bar1: Bar,
) {
    // body
}

class Foo(
    val bar1: Bar,
    val bar2: Bar,
) {
    // body
}

class Foo : FooBar("bar") {
    // body
}

class Foo : FooBar("bar1", "bar2") {
    // body
}

class Foo :
    FooBar(
        "bar1",
        "bar2",
    ) {
    // body
}

class Foo :
    FooBar(
        "bar1",
        "bar2",
    ) {
    // body
}

class Foo(
    val bar1: Bar,
) : FooBar(bar1) {
    // body
}

class Foo(
    val bar1: Bar,
    val bar2: Bar,
) : FooBar(bar1) {
    // body
}

class Foo(
    val bar1: Bar,
    val bar2: Bar,
) : FooBar(bar1, bar2) {
    // body
}

class Foo(
    val bar1: Bar,
    val bar2: Bar,
) : FooBar(
        bar1,
        bar2,
    ) {
    // body
}

class Foo(
    val bar1: Bar,
    val bar2: Bar,
) : FooBar(
        bar1,
        bar2,
    ) {
    // body
}

class Foo :
    FooBar("bar"),
    BarFoo1,
    BarFoo2 {
    // body
}

class Foo :
    FooBar("bar1", "bar2"),
    BarFoo1,
    BarFoo2 {
    // body
}

class Foo :
    FooBar(
        "bar1",
        "bar2",
    ),
    BarFoo1,
    BarFoo2 {
    // body
}

class Foo :
    FooBar(
        "bar1",
        "bar2",
    ),
    BarFoo1,
    BarFoo2 {
    // body
}

class Foo :
    FooBar(
        "bar1",
        "bar2",
    ),
    BarFoo1,
    BarFoo2 {
    // body
}

class Foo(
    val bar1: Bar,
    val bar2: Bar,
) : FooBar(bar1, bar2),
    BarFoo1,
    BarFoo2 {
    // body
}

class Foo(
    val bar1: Bar,
    val bar2: Bar,
) : FooBar(
        bar1,
        bar2,
    ),
    BarFoo1,
    BarFoo2 {
    // body
}

class Foo(
    val bar1: Bar,
    val bar2: Bar,
) : FooBar(
        bar1,
        bar2,
    ),
    BarFoo1,
    BarFoo2 {
    // body
}

class Foo
    constructor(
        val bar1: Bar,
        val bar2: Bar,
    ) : FooBar(bar1, bar2),
        BarFoo1,
        BarFoo2 {
    // body
}

while in code styles intellij_idea and android_studio it is formatted as:

class Foo {
    // body
}

class Foo {
    // body
}

class Foo(val bar1: Bar) {
    // body
}

class Foo(
    val bar1: Bar,
    val bar2: Bar,
) {
    // body
}

class Foo : FooBar("bar") {
    // body
}

class Foo : FooBar("bar1", "bar2") {
    // body
}

class Foo :
    FooBar(
        "bar1",
        "bar2",
    ) {
    // body
}

class Foo :
    FooBar(
        "bar1",
        "bar2",
    ) {
    // body
}

class Foo(val bar1: Bar) : FooBar(bar1) {
    // body
}

class Foo(
    val bar1: Bar,
    val bar2: Bar,
) : FooBar(bar1) {
    // body
}

class Foo(
    val bar1: Bar,
    val bar2: Bar,
) : FooBar(bar1, bar2) {
    // body
}

class Foo(
    val bar1: Bar,
    val bar2: Bar,
) : FooBar(
    bar1,
    bar2,
) {
    // body
}

class Foo(
    val bar1: Bar,
    val bar2: Bar,
) : FooBar(
    bar1,
    bar2,
) {
    // body
}

class Foo :
    FooBar("bar"),
    BarFoo1,
    BarFoo2 {
    // body
}

class Foo :
    FooBar("bar1", "bar2"),
    BarFoo1,
    BarFoo2 {
    // body
}

class Foo :
    FooBar(
        "bar1",
        "bar2",
    ),
    BarFoo1,
    BarFoo2 {
    // body
}

class Foo :
    FooBar(
        "bar1",
        "bar2",
    ),
    BarFoo1,
    BarFoo2 {
    // body
}

class Foo :
    FooBar(
        "bar1",
        "bar2",
    ),
    BarFoo1,
    BarFoo2 {
    // body
}

class Foo(
    val bar1: Bar,
    val bar2: Bar,
) : FooBar(bar1, bar2),
    BarFoo1,
    BarFoo2 {
    // body
}

class Foo(
    val bar1: Bar,
    val bar2: Bar,
) : FooBar(
    bar1,
    bar2,
),
    BarFoo1,
    BarFoo2 {
    // body
}

class Foo(
    val bar1: Bar,
    val bar2: Bar,
) : FooBar(
    bar1,
    bar2,
),
    BarFoo1,
    BarFoo2 {
    // body
}

class Foo
constructor(
    val bar1: Bar,
    val bar2: Bar,
) : FooBar(bar1, bar2),
    BarFoo1,
    BarFoo2 {
    // body
}

paul-dingemans added a commit that referenced this issue Jul 21, 2023
* Add rule `class-signature`. This rule rewrites the class header to a consistent format. In code style `ktlint_official`, super types are always wrapped to a separate line. In other code styles, super types are only wrapped in classes having multiple super types. Especially for code style `ktlint_official` the class headers are rewritten in a more consistent format.

Closes #875
Closes #1349

* Add disallowed comments locations for value argument, type argument, value parameter and type parameter lists so that the ClassSignatureRule does not need to check for this

* Fix indentation for class having explicit constructor in ktlint_official code style
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants