phodal/chapi

View on GitHub
chapi-ast-java/src/main/kotlin/chapi/ast/javaast/JavaBasicIdentListener.kt

Summary

Maintainability
C
7 hrs
Test Coverage
package chapi.ast.javaast

import chapi.ast.antlr.JavaParser
import chapi.domain.core.*

open class JavaBasicIdentListener(fileName: String) : JavaAstListener() {
    private var isOverrideMethod: Boolean = false
    private var hasEnterClass: Boolean = false
    private var codeContainer: CodeContainer =
        CodeContainer(FullName = fileName)
    private var classNodes: List<CodeDataStruct> = listOf()
    private var imports: List<CodeImport> = listOf()

    private var currentNode = CodeDataStruct()
    private var currentFunction = CodeFunction(IsConstructor = false)

    override fun enterImportDeclaration(ctx: JavaParser.ImportDeclarationContext?) {
        val codeImport = CodeImport(Source = ctx!!.qualifiedName()!!.text)

        if (ctx.STATIC() != null) {
            val sourceSplit = codeImport.Source.split(".")
            codeImport.UsageName = listOf(sourceSplit.last())

            val split = sourceSplit.dropLast(1)
            codeImport.Source = split.joinToString(".")
        }

        imports += codeImport
        codeContainer.Imports += codeImport
    }

    override fun enterPackageDeclaration(ctx: JavaParser.PackageDeclarationContext?) {
        codeContainer.PackageName = ctx?.qualifiedName()!!.text
    }

    override fun enterClassDeclaration(ctx: JavaParser.ClassDeclarationContext?) {
        hasEnterClass = true
        currentNode.Type = DataStructType.CLASS
        currentNode.Package = codeContainer.PackageName
        currentNode.NodeName = ctx?.identifier()?.text ?: ""
        currentNode.Extend = ctx?.typeType()?.text ?: ""

        if (ctx?.IMPLEMENTS() != null) {
            currentNode.Implements = buildImplements(ctx)
        }

        currentFunction = CodeFunction()
    }

    override fun exitClassBodyDeclaration(ctx: JavaParser.ClassBodyDeclarationContext?) {
        hasEnterClass = false
        if (currentNode.NodeName != "") {
            classNodes += currentNode
        }
        currentNode = CodeDataStruct()
    }

    open fun buildImplements(ctx: JavaParser.ClassDeclarationContext): List<String> {
        return ctx.typeList()
            .map { it.text }
            .filter { imports.containsType(it) }
    }

    private fun <T> List<T>.containsType(it: String?): Boolean {
        return imports.filter { imp -> imp.Source.endsWith(".$it") }.toTypedArray().isNotEmpty()
    }

    open fun buildImplements(ctx: JavaParser.EnumDeclarationContext): List<String> {
        val typeText = ctx.typeList().text
        return when {
            imports.containsType(typeText) -> listOf(typeText)
            else -> listOf()
        }
    }

    override fun enterInterfaceDeclaration(ctx: JavaParser.InterfaceDeclarationContext?) {
        hasEnterClass = true
        currentNode = CodeDataStruct(
            NodeName = ctx!!.identifier().text,
            Type = DataStructType.INTERFACE,
            Package = codeContainer.PackageName
        )
    }

    override fun exitInterfaceDeclaration(ctx: JavaParser.InterfaceDeclarationContext?) {
        hasEnterClass = false
        if (currentNode.NodeName != "") {
            classNodes += currentNode
        }
    }

    override fun enterMethodDeclaration(ctx: JavaParser.MethodDeclarationContext?) {
        val name = ctx!!.identifier().text
        val typeType = ctx.typeTypeOrVoid().text

        val codeFunction = CodeFunction(
            Name = name,
            ReturnType = typeType,
            Position = buildPosition(ctx),
            IsConstructor = false,
            BodyHash = ctx.methodBody().text.hashCode()
        )

        when (val mayModifierCtx = ctx.parent.parent.getChild(0)) {
            is JavaParser.ModifierContext -> {
                codeFunction.Annotations = this.buildAnnotationForMethod(mayModifierCtx)
            }
        }

        currentFunction = codeFunction

        when (val child = ctx.parent.parent) {
            is JavaParser.ClassBodyDeclarationContext -> {
                currentFunction.Modifiers = child.modifier()
                    .map { it.text }
                    .filter { "@" in it }
            }
        }

        isOverrideMethod = false
    }

    override fun exitMethodDeclaration(ctx: JavaParser.MethodDeclarationContext?) {
        currentNode.Functions += currentFunction
        currentFunction = CodeFunction()
    }

    override fun enterInterfaceMethodDeclaration(ctx: JavaParser.InterfaceMethodDeclarationContext?) {
        val name = ctx!!.interfaceCommonBodyDeclaration().identifier().text
        val typeType = ctx.interfaceCommonBodyDeclaration().typeTypeOrVoid().text

        val codeFunction = CodeFunction(
            Name = name,
            ReturnType = typeType,
            Position = buildPosition(ctx),
            IsConstructor = false
        )

        when (val mayModifierCtx = ctx.parent.parent.getChild(0)) {
            is JavaParser.ModifierContext -> {
                codeFunction.Annotations = this.buildAnnotationForMethod(mayModifierCtx)
            }
        }

        currentFunction = codeFunction
    }

    override fun exitInterfaceMethodDeclaration(ctx: JavaParser.InterfaceMethodDeclarationContext?) {
        currentNode.Functions += currentFunction
        currentFunction = CodeFunction()
    }

    override fun enterConstructorDeclaration(ctx: JavaParser.ConstructorDeclarationContext?) {
        val codePosition = buildPosition(ctx!!)
        val codeFunction = CodeFunction(
            Name = ctx.identifier().text,
            ReturnType = "",
            Override = isOverrideMethod,
            Position = codePosition,
            IsConstructor = true
        )

        when (val modifier = ctx.parent.parent.getChild(0)) {
            is JavaParser.ModifierContext -> {
                codeFunction.Annotations = this.buildAnnotationForMethod(modifier)
            }
        }

        currentFunction = codeFunction
    }

    override fun exitConstructorDeclaration(ctx: JavaParser.ConstructorDeclarationContext?) {
        currentNode.Functions += currentFunction
    }

    override fun enterExpression(ctx: JavaParser.ExpressionContext?) {
        when (val parent = ctx!!.parent) {
            is JavaParser.StatementContext -> {
                val firstChild = parent.getChild(0).text

                if (firstChild.lowercase() == "return") {
                    val isReturnNull = ctx.text == "null"
                    currentFunction.addExtension("IsReturnNull", isReturnNull.toString())
                }
            }
        }
    }

    override fun enterEnumDeclaration(ctx: JavaParser.EnumDeclarationContext?) {
        hasEnterClass = true
        currentNode.Type = DataStructType.ENUM
        currentNode.Package = codeContainer.PackageName

        currentNode.NodeName = ctx?.identifier()?.text ?: ""

        if (ctx?.IMPLEMENTS() != null) {
            currentNode.Implements = buildImplements(ctx)
        }

        currentFunction = CodeFunction()
    }

    override fun exitEnumBodyDeclarations(ctx: JavaParser.EnumBodyDeclarationsContext?) {
        hasEnterClass = false
        if (currentNode.NodeName != "") {
            classNodes += currentNode
        }
        currentNode = CodeDataStruct()
    }

    fun getNodeInfo(): CodeContainer {
        codeContainer.DataStructures = classNodes
        return codeContainer
    }
}