Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
org.jetbrains.kotlin.javac.resolve.ClassifierResolver.kt Maven / Gradle / Ivy
package org.jetbrains.kotlin.javac.resolve
import com.sun.source.tree.CompilationUnitTree
import com.sun.source.tree.Tree
import com.sun.tools.javac.tree.JCTree
import org.jetbrains.kotlin.javac.JavacWrapper
import org.jetbrains.kotlin.load.java.structure.*
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
class ClassifierResolver (private val javac: JavacWrapper ) {
private val cache = hashMapOf()
private val beingResolved = hashSetOf()
fun resolve (tree: Tree, unit: CompilationUnitTree, containingElement: JavaElement ): JavaClassifier? {
val result = cache[tree]
if (result != null ) return result
if (tree in beingResolved ) return null
beingResolved (tree )
return tryToResolve (tree, unit, containingElement ).apply {
cache[tree] = this
removeBeingResolved (tree )
}
}
private fun beingResolved (tree: Tree ) {
if (tree is JCTree.JCTypeApply) {
beingResolved(tree.clazz)
}
if (tree is JCTree.JCFieldAccess) {
beingResolved.add (tree)
beingResolved(tree.selected)
}
else beingResolved.add (tree)
}
private fun removeBeingResolved (tree: Tree ) {
if (tree is JCTree.JCTypeApply) {
beingResolved(tree.clazz)
}
if (tree is JCTree.JCFieldAccess) {
beingResolved.remove (tree)
beingResolved(tree.selected)
}
else beingResolved.remove (tree)
}
private fun pathSegments (path: String ): List {
val pathSegments = arrayListOf()
var numberOfBrackets = 0
val builder = StringBuilder()
path.forEach { char ->
when (char ) {
'<' -> numberOfBrackets++
'>' -> numberOfBrackets--
'.' -> {
if (numberOfBrackets == 0 ) {
pathSegments.add (builder.toString())
builder.setLength(0 )
}
}
'@' -> {}
else -> if (numberOfBrackets == 0 ) builder.append(char )
}
}
return pathSegments.apply { add (builder.toString()) }
}
private fun tryToResolve (tree: Tree, unit: CompilationUnitTree, containingElement: JavaElement ): JavaClassifier? {
val pathSegments = pathSegments(tree.toString())
val containingClass = when (containingElement) {
is JavaClass -> containingElement
is JavaTypeParameterListOwner -> {
pathSegments.singleOrNull()?.let { pathSegment ->
val identifier = Name.identifier(pathSegment)
containingElement.typeParameters.find { it.name == identifier }?.let { return it }
}
(containingElement as JavaMember).containingClass
}
is JavaPackage -> return SingleTypeImportScope(javac, unit).findClass(pathSegments.first(), pathSegments)
else -> throw UnsupportedOperationException()
}
return CurrentClassAndInnerScope(javac, unit, containingClass).findClass(pathSegments.first(), pathSegments)
}
}
private abstract class Scope (protected val javac: JavacWrapper,
protected val compilationUnit: CompilationUnitTree ) {
protected val helper = ResolveHelper(javac, compilationUnit)
abstract val parent: Scope?
abstract fun findClass (name: String, pathSegments: List ): JavaClassifier?
}
private class GlobalScope (javac: JavacWrapper,
compilationUnit: CompilationUnitTree ) : Scope (javac, compilationUnit ) {
override val parent: Scope?
get () = null
override fun findClass (name: String, pathSegments: List ): JavaClass? {
findByFqName(pathSegments)?.let { return it }
return helper.findJavaOrKotlinClass(classId("java.lang" , name))?.let { javaClass ->
helper.getJavaClassFromPathSegments(javaClass, pathSegments)
}
}
private fun findByFqName (pathSegments: List ): JavaClass? {
pathSegments.forEachIndexed { index, _ ->
if (index != 0 ) {
val packageFqName = pathSegments.take(index).joinToString(separator = "." )
helper.findPackage(packageFqName)?.let { packageName ->
val className = pathSegments.drop(index)
helper.findJavaOrKotlinClass(ClassId(packageName, Name.identifier(className.first())))?.let { javaClass ->
return helper.getJavaClassFromPathSegments(javaClass, className)
}
}
}
}
return helper.findJavaOrKotlinClass(classId("" , pathSegments.first()))?.let { javaClass ->
helper.getJavaClassFromPathSegments(javaClass, pathSegments)
}
}
}
private class ImportOnDemandScope (javac: JavacWrapper,
compilationUnit: CompilationUnitTree ) : Scope (javac, compilationUnit ) {
override val parent: Scope
get ( ) = GlobalScope(javac, compilationUnit)
override fun findClass (name: String, pathSegments: List ): JavaClassifier? {
asteriskImports()
.mapNotNullTo(hashSetOf()) { helper.findImport("$it$name" .split("." )) }
.takeIf { it.isNotEmpty() }
?.let {
return it.singleOrNull()?.let { javaClass ->
helper.getJavaClassFromPathSegments(javaClass, pathSegments)
}
}
return parent.findClass(name, pathSegments)
}
private fun asteriskImports ( ) =
compilationUnit.imports
.mapNotNull { it.qualifiedIdentifier.toString().takeIf { it.endsWith("*" ) }?.dropLast(1 ) }
}
private class PackageScope (javac: JavacWrapper,
compilationUnit: CompilationUnitTree ) : Scope (javac, compilationUnit ) {
override val parent: Scope
get ( ) = ImportOnDemandScope(javac, compilationUnit)
override fun findClass (name: String, pathSegments: List ): JavaClassifier? {
helper.findJavaOrKotlinClass(classId(compilationUnit.packageName?.toString() ?: "" , name))
?.let { javaClass ->
return helper.getJavaClassFromPathSegments(javaClass, pathSegments)
}
return parent.findClass(name, pathSegments)
}
}
private class SingleTypeImportScope (javac: JavacWrapper,
compilationUnit: CompilationUnitTree ) : Scope (javac, compilationUnit ) {
override val parent: Scope
get ( ) = PackageScope(javac, compilationUnit)
override fun findClass (name: String, pathSegments: List ): JavaClassifier? {
val imports = imports(name).toSet().takeIf { it.isNotEmpty() }
?: return parent.findClass(name, pathSegments)
imports.singleOrNull() ?: return null
return helper.findImport(imports.first().split("." ))
?.let { javaClass -> helper.getJavaClassFromPathSegments(javaClass, pathSegments) }
}
private fun imports (firstSegment: String ) =
compilationUnit.imports
.mapNotNull { it.qualifiedIdentifier.toString().takeIf { it.endsWith(".$firstSegment" ) } }
}
private class CurrentClassAndInnerScope (javac: JavacWrapper,
compilationUnit: CompilationUnitTree,
private val containingElement: JavaClass ) : Scope (javac, compilationUnit ) {
override val parent: Scope
get ( ) = SingleTypeImportScope(javac, compilationUnit)
override fun findClass (name: String, pathSegments: List ): JavaClassifier? {
val identifier = Name.identifier(name)
var enclosingClass: JavaClass? = containingElement
while (enclosingClass != null ) {
enclosingClass.typeParameters
.find { typeParameter -> typeParameter.name == identifier }
?.let { typeParameter -> return typeParameter }
helper.findInnerOrNested(enclosingClass, identifier)?.let { javaClass -> return helper.getJavaClassFromPathSegments(javaClass, pathSegments) }
if (enclosingClass.name == identifier && pathSegments.size == 1 ) return enclosingClass
enclosingClass = enclosingClass.outerClass
}
return parent.findClass(name, pathSegments)
}
}
fun classId (packageName: String = "" , className: String ) = ClassId(FqName(packageName), Name.identifier(className))