Skip to content

Commit

Permalink
Use FlexInspect for inspections rather than KSP (#941)
Browse files Browse the repository at this point in the history
  • Loading branch information
DRSchlaubi authored Jun 2, 2024
1 parent 118e388 commit 2cdf33c
Show file tree
Hide file tree
Showing 7 changed files with 153 additions and 92 deletions.
2 changes: 0 additions & 2 deletions common/src/commonMain/kotlin/entity/DiscordUser.kt
Original file line number Diff line number Diff line change
Expand Up @@ -51,8 +51,6 @@ import kotlinx.serialization.ExperimentalSerializationApi
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
import kotlinx.serialization.json.JsonNames
import kotlin.contracts.InvocationKind
import kotlin.contracts.contract

/**
* A representation of the [Discord User structure](https://discord.com/developers/docs/resources/user).
Expand Down
62 changes: 62 additions & 0 deletions inspections/BuilderDslMarker.inspection.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
import com.intellij.codeInspection.LocalQuickFix
import com.intellij.codeInspection.ProblemDescriptor
import com.intellij.openapi.project.Project
import org.intellij.lang.annotations.Language
import org.jetbrains.kotlin.idea.util.addAnnotation
import org.jetbrains.kotlin.idea.util.findAnnotation
import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.psi.KtAnnotated
import org.jetbrains.kotlin.psi.KtClass

@Language("HTML")
val htmlDescription = """
<html>
<body>
This reports subtypes of <code>dev.kord.rest.builder.RequestBuilder</code> which are not annotated with
<code>@KordDsl</code>
</body>
</html>
""".trimIndent()


val kordDslId = ClassId.fromString("dev/kord/common/annotation/KordDsl")
val requestBuilderId = ClassId.fromString("dev/kord/rest/builder/RequestBuilder")

class AddKordDsl : LocalQuickFix {
override fun getFamilyName(): String = "Add @KordDsl annotation"

override fun applyFix(project: Project, problem: ProblemDescriptor) {
problem.psiElement.parentsOfType<KtAnnotated>().first().addAnnotation(kordDslId, searchForExistingEntry = false)
}
}

val builderWithoutDslMarkerInspection = localInspection { psiFile, inspection ->

psiFile.descendantsOfType<KtClass>().forEach {
analyze(it) {
val requestBuilderClass = getClassOrObjectSymbolByClassId(requestBuilderId) ?: return@analyze
if (it.getClassOrObjectSymbol()?.isSubClassOf(requestBuilderClass) == true
&& it.findAnnotation(kordDslId) == null
&& it.hasModifier(KtTokens.PUBLIC_KEYWORD)
) {
inspection.registerProblem(
it.nameIdentifier,
"This class should be annotated with @KordDsl",
AddKordDsl()
)
}
}
}
}


listOf(
InspectionKts(
id = "BuilderDslMarker",
localTool = builderWithoutDslMarkerInspection,
name = "Reports builder's without DSL annotations",
htmlDescription = htmlDescription,
level = HighlightDisplayLevel.ERROR,
)
)
78 changes: 78 additions & 0 deletions inspections/OptionalWithoutDefault.inspection.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
import com.intellij.codeInspection.LocalQuickFix
import com.intellij.codeInspection.ProblemDescriptor
import com.intellij.openapi.project.Project
import org.intellij.lang.annotations.Language
import org.jetbrains.kotlin.idea.base.psi.setDefaultValue
import org.jetbrains.kotlin.idea.util.findAnnotation
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.psi.*

private val optionalTypes =
listOf("Optional", "OptionalBoolean", "OptionalInt", "OptionalLong", "OptionalSnowflake")
.map { "dev.kord.common.entity.optional.$it" }
.toSet()

@Language("HTML")
val htmlDescription = """
<html>
<body>
This inspection reports misusage of 'Optional' classes, when using them without a default value
Supported classes: ${optionalTypes.map { "<code>${it.substringAfterLast('.')}</code>" }}
</body>
</html>
""".trimIndent()

private class AddDefaultQuickfix(private val optionalClassName: String) : LocalQuickFix {
override fun getFamilyName(): String = "Add '${optionalClassName}.Missing' as a default value"

override fun applyFix(project: Project, problem: ProblemDescriptor) {
val factory = KtPsiFactory(project)
val optionalType = buildString {
append(optionalClassName)
append(".Missing")
if (optionalClassName == "Optional") {
append("()")
}
}
val initializer = factory.createExpression(optionalType)

val parameter = problem.psiElement as KtParameter
parameter.setDefaultValue(initializer)
}
}

val optionalWithoutDefaultInspection = localInspection { psiFile, inspection ->
val serializable = ClassId.fromString("kotlinx/serialization/Serializable")

psiFile
.descendantsOfType<KtClass>()
.filter { it.findAnnotation(serializable, withResolve = true) != null }
.flatMap(KtClass::allConstructors)
.flatMap(KtConstructor<*>::getValueParameters)
.filterNot(KtParameter::hasDefaultValue)
.filter { it.isOptionalTypeParameter() }
.forEach {
analyze(it) {
inspection.registerProblem(
it,
"This parameter should have a default value",
AddDefaultQuickfix(it.getReturnKtType().expandedClassSymbol!!.name!!.asString())
)
}
}
}

fun KtParameter.isOptionalTypeParameter() = analyze(this) {
getReturnKtType().fullyExpandedType.expandedClassSymbol?.getFQN() in optionalTypes
}

listOf(
InspectionKts(
id = "OptionalWithoutDefault",
localTool = optionalWithoutDefaultInspection,
name = "Optional without default inspection",
htmlDescription = htmlDescription,
level = HighlightDisplayLevel.NON_SWITCHABLE_ERROR,
)
)

This file was deleted.

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,3 +1 @@
dev.kord.ksp.generation.GenerationProcessorProvider
dev.kord.ksp.inspection.BuilderDslMarkerInspectionProcessorProvider
dev.kord.ksp.inspection.OptionalDefaultInspectionProcessorProvider
13 changes: 13 additions & 0 deletions qodana.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
version: "1.0"

profile:
name: qodana.recommended

exclude:
- name: All
paths:
- voice/src/main/java/com/iwebpp/crypto/TweetNaclFast.java

projectJDK: "8"

linter: jetbrains/qodana-jvm

0 comments on commit 2cdf33c

Please sign in to comment.