ktlint: Alphabetical import ordering enabled by default is a problem in Android Studio/IntelliJ

In our project ktlint 0.34.0 now reports a lot of incorrect import ordering, although we use a default import layou of IDE. All our developers have “Optimize imports” enabled by default, but this still creates an order like the following (which seems to be default one of Kotlin IDE plugin):

import ru.example.a
import ru.example.b
import ru.example.c
import javax.inject.Inject

Notice that the last one comes in non alphabetical order. The unfortunate thing is that this cannot be changed.

Import order editing is there only for Java CodeStyle, kotlin plugin seems not to provide it. Correct me if I’m wrong.

If you think that this is still something that should be default, then please close.

But currently I suspect that many Android Studio/IntelliJ users will be disabling this rule, otherwise they’ll have an endless conflict between IDE autoformatter/ktlint.

About this issue

  • Original URL
  • State: closed
  • Created 5 years ago
  • Reactions: 153
  • Comments: 51 (16 by maintainers)

Commits related to this issue

Most upvoted comments

Thanks for the report! Of course anything and everything is up for discussion; I will close this ticket for now but I will keep an eye out for feedback if this rule proves controversial.

Hi all, thanks for the feedback. @romtsn is working on a diff to address this via configs (default will be to match the IDEA ordering) and we will target the 0.37.0 release, which is scheduled to go out next week. Appreciate your patience.

Adding a property to .editorconfig – which itself is flagged by yet other linters as invalid – in order to suppress this lint issue is rather funny. I believe this ticket should be reopened. As it stands, any project with at least a single IntelliJ user (for OpenSource projects I’d argue actually all projects are impacted) has to disable this rule.

It does invalidate the claim on the ktlint README that…

…it makes Intellij IDEA’s built-in formatter produce 100% ktlint-compatible code.

If this is ‘expected behavior’, calling the cli suggested ktlint --apply-to-idea-project becomes mostly useless since a 98% match still means going to the terminal to do ktlint -F, as no one is going alphabetize imports manually (as opposed to other non-automatically fixed issues which can be fixed by user intervention with moderate effort).

fyi: IDEA puts java/javax imports at the bottom, contrary to ktlint expectations.

@dimsuz as of 0.34.0 you can disable rules via the .editorconfig: https://github.com/pinterest/ktlint#custom-editorconfig-properties

So in this case it would be disabled_rules=import-ordering

In the meantime, for those using jlleitschuh gradle plugin:

apply plugin: "org.jlleitschuh.gradle.ktlint"

ktlint {
    version = "0.36.0"
    android = true
    // See https://github.com/pinterest/ktlint/issues/527
    disabledRules = ["import-ordering"]
}

It does invalidate the claim on the ktlint README that…

…it makes Intellij IDEA’s built-in formatter produce 100% ktlint-compatible code.

If this is ‘expected behavior’, calling the cli suggested ktlint --apply-to-idea-project becomes mostly useless since a 98% match still means going to the terminal to do ktlint -F, as no one is going alphabetize imports manually (as opposed to other non-automatically fixed issues which can be fixed by user intervention with moderate effort).

Sure. I understand your frustration, I just want to make sure the IDEA Optimize Imports ordering is not going to change before mimicing the same behavior in ktlint.

That bug was open in 2016 it looks like, not sure it is going to be resolved quickly. This issue caused quite a bit of headache for us today. Is there any reason not to keep inline with Intellij until if/when it changes?

The following code block will cause ktlint to report incorrect order

import kotlinx.coroutines.CoroutineDispatcher
import kotlin.coroutines.CoroutineContext

object DirectDispatcher : CoroutineDispatcher() {
    override fun dispatch(context: CoroutineContext, block: Runnable) {
        block.run()
    }
}

This seems to be the default IJ import ordering for koltin and it mismatches ktlint.

You can also disable Android Studios optimize imports.

There is two way to do that. Run the action Show Reformat File Dialog and uncheck optimize imports

image

Otherwise, you can edit the $HOME/Library/Preferences/AndroidStudio3.5/options/other.xml and set LayoutCode.optimizeImports to false. Major drawback is this is per developer/Android-Studio version

Here is sed if that helps anyone at all.

sed -i '' \
  's/\<property name\="LayoutCode\.optimizeImports" value\="true" \/\>/\<property name\="LayoutCode\.optimizeImports" value\="false" \/\>/g' \
  "$HOME/Library/Preferences/AndroidStudio3.5/options/other.xml"

Although my settings look like this in Preferences / Editor / Code Style / Kotlin / Imports, Android Studio still puts aliased imports first which is a flagged by the import-ordering rule.

Screenshot 2022-09-16 at 12 05 11

I’m unable to get AS to organize imports the way ktlint expects it.

Android Studio Dolphin 2021.3.1 ktlint 0.47.1

We will get to a year soon with the same issue, a lot of projects having to disable the rule manually and still not removing it from ktlint because…? I think there is absolutely no excuse not to drop this rule or make it opt-in instead of opt-out, as it still invalidates the sentence:

…it makes Intellij IDEA’s built-in formatter produce 100% ktlint-compatible code.

For those watching at home, this is also fixed on the IDEA side in Kotlin plugin 1.4 - https://github.com/JetBrains/kotlin/pull/3336

So, it’s very annoying today, and it will still be annoying later. Is the kind of rule that everyone hates, but someone is really reluctant to drop… A shame.

@dimsuz - We’ve disabled the check. It would be great to have the option to have it match the IntelliJ order. i.e. still check, just with java/javax at the end.

@tasomaniac while that might be true, IJ and Android Studio do enforce ordering, so we should match that, otherwise this becomes a pain point for everyone using these IDEs and ktlint.

@fishy Yes, this is intentional as we are trying to match intellij default behavior, where java, javax and kotlin imports are coming after all others.

I don’t see how this rule would annoy anyone anymore, once the import order can be configured in IntelliJ. ktlint --apply-to-idea-project just needs to configure it correctly and after that the auto formatter and ktlint are in agreement again. And until the fix is ready on both sides, the rule can be ignored.

A linting rule for imports is good in general, since it prevents weird diffs. So I would not like to see this rule being dropped completely. And the most basic, out-of-the-box rule for import ordering is definitely the alphabetical one.

[Opinion ahead] Also, I would argue that if this rule clashes with an existing code style, then it is not the end of the world not to comply with that code style guide, as far as import ordering is concerned. Import ordering rules are primarily there to prevent weird diffs from happening. The few cases where one actually needs to read the import section of a file are not significantly improved, because the java.** and kotlin.** blocks are separated. Any import ordering rule would do, as long as everyone in the project uses it. And if any rule will do, then the simplest one is a very good choice.

I think there are two ways to proceed here: a) Allow ktlint customization so its ImportOrderingRule sorts exactly like IDEA does. For instance, add a property like kotlin_version=1.3.50, so it matches the default Kotlin implementation which is https://github.com/JetBrains/kotlin/blob/d765bebcfc5f741d560e96bf1ffe3dc668f57df0/idea/ide-common/src/org/jetbrains/kotlin/idea/util/ImportsUtils.kt#L37-L58 Of course, Kotlin implementation might change over time, that is why I suggest to add property like kotlin_version rather than a configuration “which packages to sort top or down”

b) Implement a custom rule (outside of ktlint) which is basically a copy-paste of the current Ktlint rule + IDEA-like sorter.

Frankly speaking, I would prefer a) (==embedded to Ktlint) since it would enable all ktlint users to use that transparently.

@tasomaniac , @shashachu , what do you think?

PS. It does bother me, because my current approach is disabling the rule 😦

Any further changes on this? Seems like the kotlin.* imports are being put at the bottom as well.

You also can follow this issue from Kotlin side: https://youtrack.jetbrains.com/issue/KT-10974

When that pr land in kotlin 1.4, it means kotlin code style wont force anyone for alphabetical order and let project specific configurations. That means, ktlint alphabetical order become obsolete. This rule can be removed or it can start supporting same order as Idea formatter per project.

@marukami does that disable more than just ordering? Other import optimisations that come to mind are grouping/ungrouping of imports and replacing star imports with direct imports. Does this setting en-/disable that too?

Please keep in mind that ktlint already has the android flag which changes the behavior of some rules. When the Android flag is not enabled, it is supposed to follow the official Kotlin style instead of the Android one. That’s what I understood.

And Google’s Kotlin style guide (not yet public) also matches Java and the Android Kotlin guide in that regard.

Just want to add that if the rule is changed it shouldn’t be changed for --android:

Import statements for classes, functions, and properties are grouped together in a single list and ASCII sorted.

https://developer.android.com/kotlin/style-guide#structure