/
AClassWithoutFunctionMustBeADataClass.kt
46 lines (37 loc) · 1.89 KB
/
AClassWithoutFunctionMustBeADataClass.kt
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
package org.toilelibre.libe.domaindrivendesignktrules
import org.jetbrains.kotlin.com.intellij.lang.ASTNode
import org.jetbrains.kotlin.psi.KtClass
import org.jetbrains.kotlin.psi.psiUtil.getNextSiblingIgnoringWhitespaceAndComments
import org.jetbrains.kotlin.psi.psiUtil.isAbstract
import org.toilelibre.libe.domaindrivendesignktrules.SomeHelpers.isNotAClass
import org.toilelibre.libe.domaindrivendesignktrules.SomeHelpers.methods
internal class AClassWithoutFunctionMustBeADataClass : Rule("a-class-without-function-must-be-a-data-class") {
override fun beforeVisitChildNodes(
node: ASTNode,
autoCorrect: Boolean,
emit: EmitFunction,
) {
if (node.isNotAClass()) return
val classInformation = node.psi as KtClass
val superClassName = classInformation.getColon()
?.getNextSiblingIgnoringWhitespaceAndComments(false)?.text ?: "Object"
val doesNotRequireAMethod = classInformation.isData() || classInformation.isEnum() ||
classInformation.isAnnotation() || classInformation.isAbstract() ||
(
classInformation.getColon() != null &&
!superClassName.contains("Object") && !superClassName.contains("Serializable")
)
val methods = classInformation.methods +
classInformation.companionObjects.flatMap { it.methods }
if (methods.isEmpty() && !doesNotRequireAMethod) {
emit.problemWith(node.startOffset, classInformation.fqName?.toString() ?: "(unknown class)")
}
}
private fun EmitFunction.problemWith(startOffset: Int, className: String?) =
this(
startOffset,
"This class $className does not have any function. Should not it be a data class ? In any case," +
"Domain Driven Design discourages the use of anemic classes (POJO or value objects)",
false,
)
}