Michael Evans

A bunch of technobabble.

Mastering Ktlint: A Guide to Crafting Your Own Rules

| Comments

Ktlint is a powerful linting tool for Kotlin code that helps maintain code quality and consistency. While it comes with a set of built-in rules, there may be cases where you want to create custom rules tailored to your project’s specific requirements. In this tutorial, we’ll walk you through the process of writing a custom ktlint rule that detects and removes Android Log statements from your Kotlin code.


Prerequisites

Before we dive into writing custom ktlint rules, ensure you have ktlint installed in your project. The tasks ktlintApplyToIdea and addKtlintCheckTask are provided by the ktlint Gradle plugin. If you haven’t already, include the plugin in your project by adding the following to your build.gradle.kts file:

1
2
3
plugins {
    id("org.jlleitschuh.gradle.ktlint") version "<latest-version>"
}

Once the plugin is applied, run the following command to set up ktlint in your project:

1
./gradlew ktlintApplyToIdea addKtlintCheckTask

Writing a Custom ktlint Rule

1. Create a New Module

To write a custom ktlint rule, start by creating a new module in your Kotlin project.

2. Set Up Your Project

In your new module, make sure you have ktlint as a dependency. Add it to your build.gradle.kts or build.gradle file:

1
2
3
dependencies {
    ktlint("io.gitlab.arturbosch.detekt:detekt-formatting:<ktlint-version>")
}

3. Define the ktlint Rule

Now, let’s define our custom rule. Create a Kotlin class that extends the Rule class and override the visit method to define the logic for your rule. In this example, we want to detect Android Log statements.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import io.gitlab.arturbosch.detekt.api.Rule
import org.jetbrains.kotlin.psi.KtCallExpression

class LogStatementRule : Rule() {
    override fun visitCallExpression(expression: KtCallExpression) {
        if (expression.calleeExpression?.text == "Log" &&
            expression.valueArguments.size == 1
        ) {
            // Report a finding
            report(
                finding = "Found Android Log statement",
                documentable = expression
            )
        }
    }
}

4. Create a Test

As with any code we write, it’s great practice to write tests for your custom rule to ensure it behaves as expected. Use the ktlint testing library to create a test case that demonstrates the rule’s functionality.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
import io.gitlab.arturbosch.detekt.test.lint
import org.spekframework.spek2.Spek
import org.spekframework.spek2.style.specification.describe

object LogStatementRuleSpec : Spek({
    describe("a LogStatementRule") {
        val subject = LogStatementRule()

        it("should report Android Log statements") {
            val code = """
                import android.util.Log
                fun example() {
                    Log.d("Tag", "Message")
                }
            """.trimIndent()

            subject.lint(code)
                .shouldContainOnly(subject.findings.single())
        }

        it("should not report other function calls") {
            val code = """
                fun example() {
                    someFunction()
                }
            """.trimIndent()

            subject.lint(code)
                .shouldBeEmpty()
        }
    }
})

5. Add the Rule to ktlint Configuration

To make your custom rule part of your ktlint configuration, add it to the .editorconfig file in your project:

1
2
3
# .editorconfig
# Custom ktlint rules
ktlint.ruleset = LogStatementRule

6. Run ktlint

Run ktlint in your project to check for Android Log statements and automatically remove them using the --apply-to-idea flag:

1
./gradlew ktlintApplyToIdea

Conclusion

In this tutorial, we’ve shown you how to write a custom ktlint rule to detect and remove Android Log statements from your Kotlin code. Custom ktlint rules can help you maintain code quality and consistency by enforcing project-specific coding standards. This is obviously a simple example, but this is a good example to adapt for other custom rules that fit your project’s needs.

Ktlint is a powerful tool that, when combined with custom rules, can significantly improve your Kotlin codebase’s quality and readability. Happy coding!

Comments