DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Refcards Trend Reports
Events Video Library
Refcards
Trend Reports

Events

View Events Video Library

Related

  • Why Kotlin Multiplatform is a Game-Changer for Startup Teams
  • Kotlin Code Style: Best Practices for Former Java Developers
  • Metal and the Simulated Annealing Algorithm
  • Reactive Kafka With Spring Boot

Trending

  • The Developer's Guide to Context-Aware AI: When Your Code Documentation Becomes Intelligent
  • Engineering LLMOps: Building Robust CI/CD Pipelines for LLM Applications on Google Cloud
  • Querying Without a Query Language
  • Why Your DLP Policies Fall Short the Moment AI Agents Enter the Picture
  1. DZone
  2. Coding
  3. Languages
  4. A SonarQube Plugin for Kotlin: Creating the Plugin

A SonarQube Plugin for Kotlin: Creating the Plugin

After parsing the code and creating the checks, this series on SonarQube plugins goes into coding up an actual plugin for custom-developed violations.

By 
Nicolas Fränkel user avatar
Nicolas Fränkel
·
Updated Jun. 28, 17 · Tutorial
Likes (1)
Comment
Save
Tweet
Share
7.8K Views

Join the DZone community and get the full member experience.

Join For Free

This is the third post in a series about creating a SonarQube plugin for the Kotlin language:

  • The first post was about creating the parsing code itself.
  • The second post detailed how to use the parsing code to check for two rules.

In this final post, we will be creating the plugin proper using the code of the 2 previous posts.

The Sonar Model

The Sonar model is based on the following abstractions:

Plugin

Entry-point for plugins to inject extensions into SonarQube

A plugin points to the other abstraction instances to make the SonarQube platform load them

AbstractLanguage

Pretty self-explanatory. Represents a language: Java, C#, Kotlin, etc.

ProfileDefinition

Define a profile which is automatically registered during sonar startup

A profile is a mutable set of fully configured rules. While not strictly necessary, having a Sonar profile pre-registered allows users to analyze their code without further configuration. Every language plugin offered by Sonar has at least one profile attached.

RulesDefinition

Defines some coding rules of the same repository

Defines an immutable set of rule definitions into a repository. While a rule definition defines available parameters, default severity, etc. the rule (from the profile) defines the exact value for parameters, a specific severity, etc. In short, the rule implements the role definition.

Sensor

A sensor is invoked once for each module of a project, starting from leaf modules. The sensor can parse a flat file, connect to a web server... Sensors are used to add measure and issues at file level.

The sensor is the entry-point where the magic happens.

Starting to Code the Plugin

Every abstraction above needs a concrete subclass. Note that the API classes themselves are all fairly decoupled. It’s the role of the Plugin child class to bind them together.

class KotlinPlugin : Plugin {

    override fun define(context: Context) {
        context.addExtensions(
                Kotlin::class.java,
                KotlinProfile::class.java,
                KotlinSensor::class.java,
                KotlinRulesDefinition::class.java)
    }
}


Most of the code is mainly boilerplate, but for ANTLR code.

Wiring the ANTLR Parsing Code

On one hand, the parsing code is based on generated listeners. On the other hand, the sensor is the entry-point to the SonarQube parsing. There’s a need for a bridge between the two.

In the first article, we used an existing grammar for Kotlin to generate parsing code. SonarQube provides its own lexer/parser generating tool (SonarSource Language Recognizer). A sizeable part of the plugin API is based on it. Describing the grammar is no small feat for any real-life language, so I preferred to design my own adapter code instead.

AbstractKotlinParserListener

Subclass of the generated ANTLR KotlinParserBaseListener. It has an attribute to store violations, and a method to add such a violation.

Violation

The violation only contains the line number, as the rest of the required information will be stored into a KotlinCheck instance.

KotlinCheck

Abstract class that wraps an AbstractKotlinParserListener. Defines what constitutes a violation. It handles the ANTLR boilerplate code itself.

This can be represented as the following:

The Sensor

The general pseudo-code should look something akin to:

FOR EACH source file
    FOR EACH rule
        Check for violation of the rule
        FOR EACH violation
            Call the SonarQube REST API to create a violation in the datastore


This translates as:

class KotlinSensor(private val fs: FileSystem) : Sensor {

    val sources: Iterable<InputFile>
        get() = fs.inputFiles(MAIN)

    override fun execute(context: SensorContext) {
        sources.forEach { inputFile: InputFile ->
            KotlinChecks.checks.forEach { check ->
                val violations = check.violations(inputFile.file())
                violations.forEach { (lineNumber) ->
                    with(context.newIssue().forRule(check.ruleKey())) {
                        val location = newLocation().apply {
                            on(inputFile)
                            message(check.message)
                            at(inputFile.selectLine(lineNumber))
                        }
                        at(location).save()
                    }
                }
            }
        }
    }
}


Finally, the Run

Let’s create a dummy Maven project with two classes, Test1 and Test2 in one Test.kt file, with the same code as last week. Running mvn sonar:sonar yields the following output:

Image title

Et voilà, our first SonarQube plugin for Kotlin, checking for our custom-developed violations.

Of course, it has (a lot of) room for improvements:

  • Rules need to be activated through the GUI: I couldn’t find how to do it programmatically
  • Adding new rules needs updates to the plugin. Rules in third-party plugins are not added automatically, as could be the case for standard SonarQube plugins.
  • So far, code located outside of classes seems not to be parsed.
  • The walk through the parse tree is executed for every check. An obvious performance gain would be to walk only once and do every check from there.
  • A lof of the above improvements could be achieved by replacing ANTLR’s grammar with Sonar’s internal SSLR
  • No tests…

That still makes the project a nice starting point for a full-fledged Kotlin plugin. Pull requests are welcome!

The complete source code for this post can be found on GitHub in Maven format.

To Go Further

  • Developing a SonarQube plugin
  • Supporting new languages in SonarQube
Kotlin (programming language)

Published at DZone with permission of Nicolas Fränkel. See the original article here.

Opinions expressed by DZone contributors are their own.

Related

  • Why Kotlin Multiplatform is a Game-Changer for Startup Teams
  • Kotlin Code Style: Best Practices for Former Java Developers
  • Metal and the Simulated Annealing Algorithm
  • Reactive Kafka With Spring Boot

Partner Resources

×

Comments

The likes didn't load as expected. Please refresh the page and try again.

  • RSS
  • X
  • Facebook

ABOUT US

  • About DZone
  • Support and feedback
  • Community research

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Core Program
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 3343 Perimeter Hill Drive
  • Suite 215
  • Nashville, TN 37211
  • [email protected]

Let's be friends:

  • RSS
  • X
  • Facebook