All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.toilelibre.libe.domaindrivendesignktrules.NoForOrWhileInActionClass.kt Maven / Gradle / Ivy

package org.toilelibre.libe.domaindrivendesignktrules

import org.jetbrains.kotlin.com.intellij.lang.ASTNode
import org.jetbrains.kotlin.psi.KtClass
import org.jetbrains.kotlin.psi.KtDoWhileExpression
import org.jetbrains.kotlin.psi.KtForExpression
import org.jetbrains.kotlin.psi.KtLoopExpression
import org.jetbrains.kotlin.psi.KtWhileExpression
import org.jetbrains.kotlin.psi.psiUtil.startOffset
import org.toilelibre.libe.domaindrivendesignktrules.SomeHelpers.allThe
import org.toilelibre.libe.domaindrivendesignktrules.SomeHelpers.annotationNames
import org.toilelibre.libe.domaindrivendesignktrules.SomeHelpers.isNotAClass
import org.toilelibre.libe.domaindrivendesignktrules.SomeHelpers.methods

class NoForOrWhileInActionClass : Rule("no-for-or-while-in-action-class") {

    override fun beforeVisitChildNodes(
        node: ASTNode,
        autoCorrect: Boolean,
        emit: EmitFunction
    ) {
        if (node.isNotAClass()) return

        val classInformation = node.psi as KtClass

        val methods = classInformation.methods +
            classInformation.companionObjects.flatMap { it.methods }

        if (!classInformation.annotationNames.contains("Action")) return

        val allTheLoops = methods
            .flatMap { it.bodyBlockExpression?.statements ?: emptyList() }
            .allThe()

        if (allTheLoops.isNotEmpty()) {
            allTheLoops.map {
                emit.problemWith(
                    it.startOffset,
                    when (it) {
                        is KtForExpression -> "for(. in .)"
                        is KtWhileExpression -> "while(...){...}"
                        is KtDoWhileExpression -> "do{...}while"
                        else -> "loop"
                    }
                )
            }
        }
    }

    private fun EmitFunction.problemWith(
        startOffset: Int,
        kindOfLoop: String
    ) =
        this(
            startOffset,
            """Action contains a `$kindOfLoop`, this is discouraged.
The business logic must be written in declarative programming.
If you need to tell your reader that you are iterating over a group,
you can consider implementing some idiomatics :
(e.g. : forEachUserCalled {traveler ->...})""",
            false
        )
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy