Mobile Development 18 min read

How to Build a Real‑Time Kotlin Lint IDE Plugin for Android Development

This article explains the motivation, design, implementation, and deployment of a Kotlin static‑analysis IDE plugin that provides real‑time code‑style checks for Android developers, covering tool exploration, AST/PSI parsing, rule creation, architecture layers, and practical installation steps.

Zhenai.com Front-end Tech Team
Zhenai.com Front-end Tech Team
Zhenai.com Front-end Tech Team
How to Build a Real‑Time Kotlin Lint IDE Plugin for Android Development

Introduction

Since Google announced official Kotlin support for Android at I/O 2017, Kotlin has become one of the most loved languages on Stack Overflow and the fastest‑growing language on GitHub. It is now the primary language for Android app development, and many Jetpack APIs are first released for Kotlin. However, developers still need a reliable way to enforce coding standards while writing Kotlin code.

Background

At Zhenai.com, new and existing projects switched to Kotlin in 2018 because of its null‑safety, extension functions, and functional‑programming features, which improve readability and development speed. Nevertheless, misuse of features such as companion objects can introduce performance overhead, and many developers coming from Java make simple mistakes, as shown in the companion‑object example below.

class Test {
    companion object {
        val A = "Hello"
    }
}

public class Client {
    public void say(){
        LogUtils.d(Test.Companion.getA());
    }
}

When compiled to Java, the code becomes more verbose and the access path to the constant is unnecessarily indirect.

Need for a Real‑Time IDE Plugin

Although Zhenai already uses a Sonar‑based static‑analysis platform, the feedback is only available after the code is written and scanned, which delays remediation. Java developers benefit from mature IDE plugins such as P3C, PMD, and CheckStyle, but Kotlin lacks a comparable open‑source solution. The desired plugin must install easily, parse Kotlin files statically, provide real‑time IDE warnings, and allow custom rule definitions.

Code‑Scanning Tool Exploration

Existing open‑source tools were evaluated:

Android Lint – powerful but brings a large dependency footprint when packaged as an IDE plugin.

Detekt – rich rule set but custom rule creation is cumbersome and results are only shown in the console.

KLint – focuses on style only and would require extensive modification.

Because of these limitations, a dedicated Kotlin lint plugin was decided.

Knowledge Preparation

Developing the plugin requires understanding:

Basic IDE‑plugin development workflow.

AST and PSI concepts.

Kotlin syntax‑tree parsing.

AST and PSI

AST (Abstract Syntax Tree) represents source code as a tree after the first parsing step. Android Lint originally used Lombok‑AST, later switched to IntelliJ PSI. PSI (Program Structure Interface) is the hierarchical representation of a file used by the IDE. The plugin converts Kotlin files to PSI via the kotlin‑compiler‑embeddable library, then transforms PSI into a custom AST for rule checking.

Kotlin Code Parsing Flow

The plugin uses KotlinConverter to turn a Kotlin file into PSI, then traverses the PSI to build a custom AST. This AST is visited by rule implementations to detect violations.

Plugin Architecture

The plugin consists of several layers:

Plugin layer – entry point shown in the IDE UI.

Client layer – calls the static‑analysis engine and returns problems.

Checks Rule Set layer – contains rule implementations (e.g., comment rules, complexity rules, empty‑block rules, performance rules, API‑call conventions).

Example Rule: TooManyParametersCheck

class TooManyParametersCheck : ICheck {
    private val DEFAULT_MAX = 7
    var max = DEFAULT_MAX
    private val sIssue = SIssue.SIssueBuilder()
        .name("方法参数过多检查")
        .issueId("TooManyParametersCheck")
        .des("方法参数过多,超过" + DEFAULT_MAX + "个").build()

    override fun initialize(init: InitContext) {
        init.register(FunctionDeclarationTree::class.java) { ctx, tree ->
            if (!tree.isConstructor && !isOverrideMethod(tree) && tree.formalParameters().size > max) {
                if (tree.name() == null) ctx.reportIssue(tree, sIssue) else ctx.reportIssue(tree.name()!!, sIssue)
            }
        }
    }

    override fun getSIssue(): SIssue = sIssue
}

private fun isOverrideMethod(tree: FunctionDeclarationTree): Boolean {
    return tree.modifiers().anyMatch { mod ->
        mod is ModifierTree && mod.kind() == ModifierTree.Kind.OVERRIDE
    }
}

The rule registers a listener for FunctionDeclarationTree, checks the number of parameters, and reports an issue when the count exceeds the configured maximum.

Installation and Usage

The plugin can be installed from the JetBrains Marketplace or via a local zip file. After installation, developers can scan a single file, an entire project, or enable a “before commit” check that blocks commits containing violations.

Final Workflow

With the real‑time reminder plugin, developers receive immediate feedback while coding, a pre‑commit scan prevents non‑compliant code from entering the repository, and a CI‑based Sonar scan provides additional post‑commit analysis.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

AndroidASTKotlinstatic analysisPSIIDE plugincode linting
Zhenai.com Front-end Tech Team
Written by

Zhenai.com Front-end Tech Team

Official account of Zhenai.com Front-end Tech Team, sharing our insights and practices on development quality, efficiency, performance optimization, security, and front-end research across Android, iOS, H5, mini‑programs, games, Node.js, full‑stack, and engineering.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.