JetBrains Platform
Plugin and extension development for JetBrains products.
Qodana erweitern: Benutzerdefinierte Codeinspektionen erstellen
Qodana ist ein statisches Codeanalyse-Tool, das Codeinspektionen und Quick-Fixes aus JetBrains-IDEs in Continuous-Integration-Systeme einbindet. Es kann in der Cloud oder in einem Docker-Container ausgeführt, in CI/CD-Pipelines integriert oder in einer JetBrains-IDE aufgerufen werden.
Qodana bringt von Haus aus eine beeindruckende Reihe von Inspektionen mit, ist jedoch nicht auf diese beschränkt. Sie können selbst definierte Inspektionen hinzufügen, um projektspezifische Anforderungen und Konventionen durchzusetzen.
Nehmen wir zum Beispiel an, Sie haben ein Projekt mit folgender Codekonvention:
Jede Kotlin-Klasse in einem
service-Paket muss aufServiceenden.
com.jetbrains.service.JetComponent würde nicht dieser Konvention entsprechen, com.jetbrains.service.BrainComponentService hingegen schon. Im Folgenden erstellen wir ein Plugin, das diese Inspektion implementiert, sodass Qodana diese Konvention in zukünftigen Projekten durchsetzen kann.
Wir können diese Codekonvention implementieren, indem wir eine benutzerdefinierte Codeinspektion erstellen, die in einem Plugin bereitgestellt wird. Qodana-Plugins werden ähnlich wie JetBrains-IDE-Plugins entwickelt, das heißt, wir müssen einfach ein IntelliJ-Plattform-Plugin erstellen, das in Qodana ausgeführt werden kann. Hier ist ein kurzer Überblick über die Schritte, die wir durchführen werden:
- Projekt aus dem IntelliJ Platform Plugin Template initialisieren.
- Die Projekteigenschaften und die Plugin-Beschreibung anpassen, zusammen mit den benötigten Abhängigkeiten.
- Die lokale Inspektion in der Plugin-Beschreibung deklarieren und in Kotlin implementieren.
- Das Plugin kompilieren und ein Paket erstellen.
- Im Beispielprojekt das Plugin-Artefakt in ein geeignetes Verzeichnis kopieren.
- Die Qodana-Konfigurationsdatei anpassen.
- Qodana starten und den Bericht überprüfen.
Plugin-Projekt vorbereiten
Um das Projekt zu starten, besuchen Sie das Repository IntelliJ Platform Plugin Template und klicken Sie auf die Schaltfläche Use this template, um ein Plugin-Repository zu erstellen. Geben Sie als Namen classname-inspection-qodana-plugin ein, kopieren Sie die Projekt-URL und öffnen Sie sie in IntelliJ IDEA. Wenn das Projekt einsatzbereit ist, passen Sie die Datei gradle.properties an, indem Sie pluginGroup, pluginName und pluginRepositoryUrl entsprechend deklarieren. Vergessen Sie nicht, auf die schwebende Schaltfläche Sync Gradle Changes zu klicken, um die Änderungen zu übernehmen. Um den eindeutigen Plugin-Bezeichner zu ändern, modifizieren Sie den Eintrag id in der Plugin-Beschreibungsdatei plugin.xml.
Abhängigkeiten deklarieren
Unsere Codeinspektion gilt für Kotlin-Klassen, daher müssen wir das Kotlin-Plugin zu den Abhängigkeiten des Qodana-Plugins hinzufügen. In der Datei gradle.properties müssen Sie Folgendes deklarieren:
platformBundledPlugins = org.jetbrains.kotlin
Darüber hinaus muss in den Abhängigkeiten der Plugin-Beschreibungsdatei plugin.xml dasselbe gebündelte Kotlin-Plugin enthalten sein:
org.jetbrains.kotlin
Achten Sie wieder darauf, die Gradle-Änderungen zu synchronisieren, indem Sie auf die schwebende Schaltfläche klicken.
Darüber hinaus muss die Kotlin-Klasseninspektion den Kotlin-Compiler K2 unterstützen, der seit Version 2025.1 der IntelliJ-Plattform standardmäßig aktiviert ist. Deklarieren Sie in der Plugin-Beschreibungsdatei die Erweiterung org.jetbrains.kotlin.supportsKotlinPluginMode.
Codeinspektion erstellen
Der tatsächliche Code für jede Codeinspektion für Kotlin-Klassen erfordert drei Schritte:
- Eine
com.intellij.localInspection-Erweiterung in der Plugin-Beschreibungsdatei deklarieren, zusammen mit den benötigten Attributen und einem vollständig qualifizierten Verweis auf die Implementierungsklasse. - Eine Implementierungsklasse erstellen – vorzugsweise in Kotlin.
- Eine separate HTML-Datei mit einer Beschreibung der Inspektion, der Nutzungsanleitung und einem Beispiel anlegen.
Erweiterung deklarieren
Tragen Sie die folgende Deklaration in die Plugin-Beschreibungsdatei plugin.xml ein:
Das Attribut language gibt an, dass die Inspektion für Kotlin-Quellcodedateien gilt. Es ist wichtig, die Inspektion explizit als standardmäßig aktiviert zu deklarieren, da Qodana sie andernfalls nicht ausführt. Geben Sie anschließend einen leicht lesbaren, aussagekräftigen Anzeigenamen unter displayName ein, der im Bericht und in den Einstellungen angezeigt werden soll. Das Attribut groupName legt die Inspektionskategorie fest, die sowohl im Qodana-Bericht als auch in den IDE-Einstellungen angezeigt wird. Geben Sie schließlich einen vollständig qualifizierten Namen für die Implementierungsklasse ein.
Quellcode der Codeinspektion
Das Kotlin-Plugin stellt eine nützliche Basis-Inspektionsklasse für Kotlin-Inspektionen bereit: AbstractKotlinInspection. Überschreiben Sie die Methode buildVisitor und stellen Sie eine PSI-Visitor-Instanz bereit, die die Kotlin-Klassenelemente auf typsichere Weise durchläuft. classVisitor ist eine praktische DSL-ähnliche Funktion, die den benötigten PSI-Visitor zurückgibt und für jede Kotlin-Klasse im analysierten Projekt aufgerufen wird.
package org.intellij.sdk.codeInspection
import com.intellij.codeInspection.ProblemHighlightType
import com.intellij.codeInspection.ProblemsHolder
import com.intellij.psi.PsiElementVisitor
import org.jetbrains.kotlin.idea.codeinsight.api.classic.inspections.AbstractKotlinInspection
import org.jetbrains.kotlin.psi.KtClass
import org.jetbrains.kotlin.psi.KtVisitorVoid
import org.jetbrains.kotlin.psi.classVisitor
class ServicePackageClassNameInspection : AbstractKotlinInspection() {
override fun buildVisitor(holder: ProblemsHolder, isOnTheFly: Boolean) = classVisitor { klass ->
val classNamePsi = klass.nameIdentifier ?: return@classVisitor
val classFqn = klass.fqName?.asString() ?: return@classVisitor
if (klass.packageLastComponent == "service" && !classFqn.endsWith("Service")) {
holder.registerProblem(
classNamePsi,
"Class name in the 'service' package must have a 'Service' suffix"
)
}
}
private val KtClass.packageLastComponent: String
get() = containingKtFile.packageFqName.shortName().asString()
}
Die Visitor-Unterklasse extrahiert den vollständig qualifizierten Kotlin-Klassennamen, untersucht das äußerste rechte Paketelement und prüft dieses auf das entsprechende Suffix. Unzulässige Klassennamen werden an die ProblemsHolder-Instanz gemeldet, eingeschlossen in eine PSI-Elementklasse und mit einer für Menschen lesbaren Problembeschreibung.
Inspektionsbeschreibung
Für jede lokale Inspektion muss eine Beschreibungsdatei im HTML-Format bereitgestellt werden. Wenn Sie den Quick-Fix Create description file ServicePackageClassNameInspection.html anwenden, wird im richtigen Verzeichnis eine Datei mit dem Namen src/main/resources/inspectionDescriptions/ServicePackageClassName.html angelegt. Sie müssen auch eine Beschreibung bereitstellen, die im Qodana-Bericht und in den IDE-Einstellungen angezeigt wird.
Reports class names in theservicepackages that lack theServicesuffix. Example:
package com.example.foo.service
class SomeComponent {
/* class members */
}
Plugin kompilieren
Jetzt ist alles vorbereitet – wir können die Kompilierung starten! Führen Sie den Gradle-Task buildPlugin aus und überprüfen Sie das Artefakt build/distributions/qodana-code-inspection-0.0.1.zip, das im Gradle-Ausgabeverzeichnis bereitgestellt wird. Die JAR-Datei wird als Hauptartefakt im Qodana-Scan verwendet.
Typ des Plugin-Artefakts beachten
Qodana unterstützt keine lokalen ZIP-Plugin-Artefakte, die zusätzliche JAR-Archive oder Drittanbieter-Abhängigkeiten enthalten. Jedes Plugin muss als einzelne JAR-Datei vorliegen oder in ein bestimmtes Verzeichnis entpackt werden.
Playground-Projekt mit Qodana prüfen
Nachdem wir nun Qodana mit unserem Plugin erweitert haben, erstellen wir ein Playground-Projekt in Kotlin, das wir mit Qodana analysieren können. Um das Qodana-Plugin lokal auszuführen, stellen Sie sicher, dass zwei Softwarekomponenten auf Ihrem System verfügbar sind:
Unser Playground-Projekt sollte eine Klasse namens src/main/kotlin/org/intellij/sdk/qodana/service/SomeComponent.kt enthalten, die nicht unserer Codekonvention entspricht, da sie nicht auf Service endet. Es gibt zwei Möglichkeiten, das Qodana-Plugin in Qodana einzubinden:
- Im JetBrains Marketplace veröffentlichen.
- Das JAR-Artefakt des Plugins in das
.qodana-Verzeichnis Ihres Projekts kopieren – die schnellere Methode.
Um den Buildvorgang zu vereinfachen, kopieren Sie die Datei build/distributions/qodana-code-inspection-0.0.1.zip aus dem Plugin-Projekt in die Datei .qodana/qodana-code-inspection-0.0.1.zip im Playground-Projekt. Erstellen Sie das Verzeichnis .qodana, falls noch nicht vorhanden. Entpacken Sie anschließend das Archiv mit Ihrem bevorzugten Programm oder Tool. Qodana kann auf das Plugin im Verzeichnis build/distributions/qodana-codeinspection zugreifen.
Darüber hinaus muss Qodana so konfiguriert werden, dass es unsere benutzerdefinierte Codeinspektion verwendet. Nehmen Sie in der Datei qodana.yaml im Stammverzeichnis des Playground-Projekts die folgenden Änderungen vor:
version: "1.0" linter: qodana-jvm-community include: - name: org.intellij.sdk.codeInspection.ServicePackageClassNameInspection
Der include-Block muss auf den vollständig qualifizierten Klassennamen der vom Plugin bereitgestellten Codeinspektion verweisen. Führen Sie nun im Terminal den folgenden Befehl aus, um Qodana zu starten:
qodana scan --volume $PWD/.qodana/qodana-code-inspection:/opt/idea/custom-plugins/qodana-code-inspection
Dadurch wird das entsprechende Qodana-Docker-Image heruntergeladen. Ein Docker-Container wird erstellt und unter Verwendung der Qodana-Konfiguration ausgeführt. Damit das benutzerdefinierte Plugin für Qodana erreichbar ist, mounten Sie das Qodana-Plugin-Verzeichnis aus dem lokalen Dateisystem in das entsprechende Verzeichnis des Qodana-Docker-Containers. Nach einigen Minuten erstellt Qodana eine Berichtszusammenfassung und gibt diese über die Standardausgabe aus.
Qodana - Detailed summary Analysis results: 1 problem detected By severity: High - 1 ------------------------------------------------------- Name Severity Problems count ------------------------------------------------------- SDK: Discouraged class name High 1 -------------------------------------------------------
Öffnen Sie den vollständigen Bericht in Ihrem Browser:
Do you want to open the latest report [Y/n]Yes ! Press Ctrl+C to stop serving the report Showing Qodana report from http://localhost:8080/... (10s)
Qodana meldet, dass SomeComponent nicht mit der Codekonvention übereinstimmt, die von unserer lokalen Inspektion im Qodana-Plugin vorgegeben wurde.

Tipps für weitere Durchläufe
Wenn das Qodana-Plugin geändert und neu kompiliert wird, muss auch der Qodana-Cache neu erstellt werden. Verwenden Sie in solchen Fällen den Befehlszeilenschalter --clear-cache, um alle Abhängigkeiten des Qodana-Laufs neu zu laden.
qodana scan --clear-cache --volume $PWD/.qodana/qodana-code-inspection-0.0.1.jar:/opt/idea/custom-plugins/codeinspection.jar
Qodana in Ihre IDE integrieren
Das Qodana-Plugin kann von der Festplatte in die IDE installiert werden. Die Codeinspektion ist dann automatisch aktiviert und wird für jede Kotlin-Klasse im untersuchten Projekt aufgerufen. Um zu überprüfen, ob es funktioniert, kehren Sie zum Playground-Projekt zurück, öffnen Sie die Klasse org.intellij.sdk.qodana.service.SomeComponent und überprüfen Sie, ob der problematische Klassenname unterkringelt ist. Wenn Sie die Maus auf den Klassennamen bewegen, werden Ihnen das Ergebnis der Codeinspektion sowie eine Beschreibung des Problems angezeigt – sehr praktisch. Alternativ können Sie das Problems-Toolfenster öffnen – dort finden Sie das Problem in der Liste aller von Codeinspektionen gemeldeten Probleme.
Die Codeinspektion verhält sich nun wie jede andere von der IDE bereitgestellte Inspektion. Unter Settings | Editor | Inspections | Kotlin finden Sie die Inspektion SDK: Discouraged class name, zusammen mit der Beschreibung aus der zuvor erstellten HTML-Datei.
Qodana in der IDE ausführen
Nachdem Sie das Plugin installiert haben, können Sie Qodana auch in Ihrer IDE ausführen. Öffnen Sie im Problems-Toolfenster die Registerkarte Qodana und klicken Sie auf die Schaltfläche Try Locally. Qodana wird mit der Konfiguration aus der Datei qodana.yaml ausgeführt. Der Qodana-Bericht wird direkt im Toolfenster bereitgestellt.

Qodana-Plugins und der JetBrains Marketplace
Korrekt erstellte und getestete benutzerdefinierte Inspektions-Plugins können im JetBrains Marketplace veröffentlicht werden – dadurch entfällt die Notwendigkeit, das Plugin im .qodana-Verzeichnis bereitzustellen. Stattdessen müssen Sie lediglich sicherstellen, dass in der Qodana-Konfiguration ein öffentlicher Plugin-Bezeichner angegeben wird, der mit dem id-Element in der Plugin-Beschreibungsdatei übereinstimmt.
version: "1.0" linter: qodana-jvm-community plugins: - id: com.github.novotnyr.qodanacodeinspection
Der scan-Befehl von Qodana kann nun einfacher ausgeführt werden, da das .qodana-Verzeichnis nicht mehr gemountet werden muss.
qodana scan
Qodana lädt das Plugin vom JetBrains Marketplace herunter und führt alle darin enthaltenen Inspektionen durch. Die Ergebnisse werden sowohl in der Konsole als auch einem HTML-Bericht ausgegeben – letzteren können Sie in einem Webbrowser betrachten.
Zusammenfassung
Wir haben ein Qodana-Plugin mit einer Codeinspektion erstellt, welche die Einhaltung einer bestimmten Codekonvention prüft, und wir haben mehrere Möglichkeiten, um die Inspektion auszuführen:
- Als JAR-Datei im Verzeichnis
.qodanaablegen und in der Qodana-YAML-Datei darauf verweisen. - Auf ein öffentlich verfügbares Plugin im JetBrains Marketplace verweisen.
- Als JAR-Datei in der IDE installieren, damit die Inspektion bei lokalen Qodana-Durchläufen ausgeführt wird.
- Als JAR-Datei in der IDE installieren, damit die Inspektion zusammen mit den eingebauten Codeinspektionen ausgeführt wird.
Im IntelliJ-SDK-Beispielcode finden Sie kurze Beispiele sowohl für das Qodana-Plugin als auch für ein Playground-Projekt.
Autor des ursprünglichen Blogposts