-
Notifications
You must be signed in to change notification settings - Fork 80
/
OptionalWithoutDefault.inspection.kts
78 lines (68 loc) · 2.77 KB
/
OptionalWithoutDefault.inspection.kts
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
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
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,
)
)