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

main.name.remal.gradle_plugins.dsl.utils.retrieveJavaSourceClassName.kt Maven / Gradle / Ivy

The newest version!
package name.remal.gradle_plugins.dsl.utils

import com.github.javaparser.JavaParser
import com.github.javaparser.ParserConfiguration
import com.github.javaparser.ParserConfiguration.LanguageLevel.RAW
import com.github.javaparser.Position
import com.github.javaparser.ast.body.TypeDeclaration
import name.remal.nullIfEmpty
import name.remal.orNull
import name.remal.queueOf
import java.io.File
import java.nio.charset.Charset
import java.nio.charset.StandardCharsets.UTF_8
import java.util.IdentityHashMap

fun retrieveClassNameFromJavaSource(sourceFile: File, line: Int? = null, column: Int? = null, charset: Charset = UTF_8): ClassName? {
    val parserConfiguration = ParserConfiguration().apply {
        languageLevel = RAW
        characterEncoding = charset
    }
    val parser = JavaParser(parserConfiguration)

    val parseResult = parser.parse(sourceFile)
    if (!parseResult.isSuccessful) return null
    val compilationUnit = parseResult.result.orNull ?: return null

    val packageName = compilationUnit.packageDeclaration.orNull?.nameAsString.nullIfEmpty()

    if (line == null) {
        val classSimpleName = compilationUnit.primaryType.orNull?.nameAsString
        val className = if (packageName == null) {
            classSimpleName
        } else {
            packageName + '.' + classSimpleName
        }
        return className
    }

    val resultClassNames: MutableMap, ClassName> = IdentityHashMap()
    val typesQueue = queueOf>()
    compilationUnit.types?.forEach { typesQueue.add(it) }
    while (true) {
        val type = typesQueue.poll() ?: break
        val begin = type.begin.filter(Position::valid).orNull ?: continue
        val end = type.end.filter(Position::valid).orNull ?: continue
        if (begin.line <= line
            && (begin.line != line || column == null || begin.column <= column)
            && end.line >= line
            && (end.line != line || column == null || end.column >= column)
        ) {
            val classSimpleName = type.nameAsString.nullIfEmpty() ?: continue

            val parent = type.parentNode.orNull
            if (parent is TypeDeclaration<*>) {
                val parentClassName = resultClassNames.remove(parent) ?: throw IllegalStateException("Parent type $parent is not processed")
                val className = parentClassName + '$' + classSimpleName
                resultClassNames[type] = className

            } else if (type.isTopLevelType) {
                val className = if (packageName == null) {
                    classSimpleName
                } else {
                    packageName + '.' + classSimpleName
                }
                resultClassNames[type] = className

            } else {
                throw IllegalStateException("Nested type $type has non-type parent: $parent")
            }

            val childTypes = type.childNodes?.filterIsInstance(TypeDeclaration::class.java) ?: emptyList()
            childTypes.forEach { typesQueue.add(it) }
        }
    }

    return resultClassNames.values.singleOrNull()
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy