Uast: support internal class names in Java and method signatures in Java and Kotlin
This commit is contained in:
@@ -28,7 +28,8 @@ interface UClass : UDeclaration, UFqNamed, UModifierOwner, UAnnotated {
|
|||||||
|
|
||||||
val companions: List<UClass>
|
val companions: List<UClass>
|
||||||
|
|
||||||
val internalName: String?
|
open val internalName: String?
|
||||||
|
get() = null
|
||||||
|
|
||||||
val superTypes: List<UType>
|
val superTypes: List<UType>
|
||||||
val declarations: List<UDeclaration>
|
val declarations: List<UDeclaration>
|
||||||
|
|||||||
@@ -25,6 +25,9 @@ interface UFunction : UDeclaration, UModifierOwner, UAnnotated {
|
|||||||
val body: UExpression
|
val body: UExpression
|
||||||
val visibility: UastVisibility
|
val visibility: UastVisibility
|
||||||
|
|
||||||
|
open val bytecodeDescriptor: String?
|
||||||
|
get() = null
|
||||||
|
|
||||||
fun getSuperFunctions(context: UastContext): List<UFunction>
|
fun getSuperFunctions(context: UastContext): List<UFunction>
|
||||||
|
|
||||||
override fun traverse(handler: UastHandler) {
|
override fun traverse(handler: UastHandler) {
|
||||||
|
|||||||
@@ -15,7 +15,10 @@
|
|||||||
*/
|
*/
|
||||||
package org.jetbrains.uast.java
|
package org.jetbrains.uast.java
|
||||||
|
|
||||||
|
import com.intellij.ide.util.JavaAnonymousClassesHelper
|
||||||
import com.intellij.psi.*
|
import com.intellij.psi.*
|
||||||
|
import com.intellij.psi.util.ClassUtil
|
||||||
|
import com.intellij.psi.util.PsiTreeUtil
|
||||||
import com.intellij.psi.util.PsiTypesUtil
|
import com.intellij.psi.util.PsiTypesUtil
|
||||||
import org.jetbrains.uast.*
|
import org.jetbrains.uast.*
|
||||||
import org.jetbrains.uast.kinds.UastClassKind
|
import org.jetbrains.uast.kinds.UastClassKind
|
||||||
@@ -59,7 +62,7 @@ class JavaUClass(
|
|||||||
override val isAnonymous: Boolean
|
override val isAnonymous: Boolean
|
||||||
get() = psi is PsiAnonymousClass
|
get() = psi is PsiAnonymousClass
|
||||||
|
|
||||||
override val internalName = null
|
override val internalName by lz { getInternalName(psi) }
|
||||||
|
|
||||||
override val superTypes by lz {
|
override val superTypes by lz {
|
||||||
psi.extendsListTypes.map { JavaConverter.convert(it, this) } + psi.implementsListTypes.map { JavaConverter.convert(it, this) }
|
psi.extendsListTypes.map { JavaConverter.convert(it, this) } + psi.implementsListTypes.map { JavaConverter.convert(it, this) }
|
||||||
@@ -98,6 +101,61 @@ class JavaUClass(
|
|||||||
|
|
||||||
return isSubClassOf(psi, name)
|
return isSubClassOf(psi, name)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private companion object {
|
||||||
|
/* Primarily copied from IntellijLintUtils and ClassContext classes from the Android IDEA plugin */
|
||||||
|
private fun getInternalName(psiClass: PsiClass): String? {
|
||||||
|
if (psiClass is PsiAnonymousClass) {
|
||||||
|
val parent = PsiTreeUtil.getParentOfType(psiClass, PsiClass::class.java)
|
||||||
|
if (parent != null) {
|
||||||
|
val internalName = getInternalName(parent) ?: return null
|
||||||
|
return internalName + JavaAnonymousClassesHelper.getName(psiClass)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var sig = ClassUtil.getJVMClassName(psiClass)
|
||||||
|
if (sig == null) {
|
||||||
|
val qualifiedName = psiClass.qualifiedName
|
||||||
|
if (qualifiedName != null) {
|
||||||
|
return getInternalName(qualifiedName)
|
||||||
|
}
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
else if (sig.indexOf('.') != -1) {
|
||||||
|
// Workaround -- ClassUtil doesn't treat this correctly!
|
||||||
|
// .replace('.', '/');
|
||||||
|
sig = getInternalName(sig)
|
||||||
|
}
|
||||||
|
return sig
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getInternalName(fqcn: String): String {
|
||||||
|
if (fqcn.indexOf('.') == -1) {
|
||||||
|
return fqcn
|
||||||
|
}
|
||||||
|
|
||||||
|
// If class name contains $, it's not an ambiguous inner class name.
|
||||||
|
if (fqcn.indexOf('$') != -1) {
|
||||||
|
return fqcn.replace('.', '/')
|
||||||
|
}
|
||||||
|
// Let's assume that components that start with Caps are class names.
|
||||||
|
val sb = StringBuilder(fqcn.length)
|
||||||
|
var prev: String? = null
|
||||||
|
for (part in fqcn.split('.')) {
|
||||||
|
if (prev != null && !prev.isEmpty()) {
|
||||||
|
if (Character.isUpperCase(prev[0])) {
|
||||||
|
sb.append('$')
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
sb.append('/')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sb.append(part)
|
||||||
|
prev = part
|
||||||
|
}
|
||||||
|
|
||||||
|
return sb.toString()
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private class JavaUAnonymousClassConstructor(
|
private class JavaUAnonymousClassConstructor(
|
||||||
|
|||||||
@@ -15,7 +15,10 @@
|
|||||||
*/
|
*/
|
||||||
package org.jetbrains.uast.java
|
package org.jetbrains.uast.java
|
||||||
|
|
||||||
|
import com.intellij.psi.PsiArrayType
|
||||||
|
import com.intellij.psi.PsiClassType
|
||||||
import com.intellij.psi.PsiMethod
|
import com.intellij.psi.PsiMethod
|
||||||
|
import com.intellij.psi.PsiType
|
||||||
import org.jetbrains.uast.*
|
import org.jetbrains.uast.*
|
||||||
import org.jetbrains.uast.psi.PsiElementBacked
|
import org.jetbrains.uast.psi.PsiElementBacked
|
||||||
|
|
||||||
@@ -53,10 +56,37 @@ class JavaUFunction(
|
|||||||
|
|
||||||
override val visibility: UastVisibility
|
override val visibility: UastVisibility
|
||||||
get() = psi.getVisibility()
|
get() = psi.getVisibility()
|
||||||
|
|
||||||
override val body by lz { JavaConverter.convertOrEmpty(psi.body, this) }
|
override val body by lz { JavaConverter.convertOrEmpty(psi.body, this) }
|
||||||
|
|
||||||
|
override val bytecodeDescriptor by lz { getDescriptor(psi) }
|
||||||
|
|
||||||
override fun getSuperFunctions(context: UastContext): List<UFunction> {
|
override fun getSuperFunctions(context: UastContext): List<UFunction> {
|
||||||
return psi.findSuperMethods().map { context.convert(it) as? UFunction }.filterNotNull()
|
return psi.findSuperMethods().map { context.convert(it) as? UFunction }.filterNotNull()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private companion object {
|
||||||
|
fun getDescriptor(psi: PsiMethod): String? {
|
||||||
|
val parameterTypes = psi.parameterList.parameters.map {
|
||||||
|
renderType(it.type) ?: return null
|
||||||
|
}
|
||||||
|
val returnType = renderType(psi.returnType) ?: return null
|
||||||
|
return parameterTypes.joinToString("", "(", ")") + returnType
|
||||||
|
}
|
||||||
|
|
||||||
|
fun renderType(type: PsiType?): String? = when (type) {
|
||||||
|
null -> null
|
||||||
|
PsiType.CHAR -> "C"
|
||||||
|
PsiType.DOUBLE -> "D"
|
||||||
|
PsiType.FLOAT -> "F"
|
||||||
|
PsiType.INT -> "I"
|
||||||
|
PsiType.LONG -> "J"
|
||||||
|
PsiType.SHORT -> "S"
|
||||||
|
PsiType.BOOLEAN -> "Z"
|
||||||
|
PsiType.VOID -> "V"
|
||||||
|
is PsiArrayType -> renderType(type.componentType)?.let { "[$it" }
|
||||||
|
is PsiClassType -> type.resolve()?.qualifiedName?.let { "L$it;" }
|
||||||
|
else -> null
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -16,11 +16,16 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.uast
|
package org.jetbrains.kotlin.uast
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.codegen.ClassBuilderMode
|
||||||
|
import org.jetbrains.kotlin.codegen.state.IncompatibleClassTracker
|
||||||
|
import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper
|
||||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||||
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
||||||
|
import org.jetbrains.kotlin.fileClasses.NoResolveFileClassesProvider
|
||||||
import org.jetbrains.kotlin.idea.caches.resolve.analyze
|
import org.jetbrains.kotlin.idea.caches.resolve.analyze
|
||||||
import org.jetbrains.kotlin.idea.caches.resolve.resolveToDescriptorIfAny
|
import org.jetbrains.kotlin.idea.caches.resolve.resolveToDescriptorIfAny
|
||||||
import org.jetbrains.kotlin.lexer.KtTokens
|
import org.jetbrains.kotlin.lexer.KtTokens
|
||||||
|
import org.jetbrains.kotlin.load.java.JvmAbi
|
||||||
import org.jetbrains.kotlin.psi.*
|
import org.jetbrains.kotlin.psi.*
|
||||||
import org.jetbrains.kotlin.resolve.BindingContext
|
import org.jetbrains.kotlin.resolve.BindingContext
|
||||||
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
|
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
|
||||||
@@ -45,6 +50,14 @@ abstract class KotlinAbstractUFunction : KotlinAbstractUElement(), UFunction, Ps
|
|||||||
}.filterNotNull()
|
}.filterNotNull()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override val bytecodeDescriptor by lz {
|
||||||
|
val bindingContext = psi.analyze(BodyResolveMode.PARTIAL)
|
||||||
|
val descriptor = bindingContext[BindingContext.DECLARATION_TO_DESCRIPTOR, psi] as? FunctionDescriptor ?: return@lz null
|
||||||
|
val typeMapper = KotlinTypeMapper(BindingContext.EMPTY, ClassBuilderMode.LIGHT_CLASSES, NoResolveFileClassesProvider, null,
|
||||||
|
IncompatibleClassTracker.DoNothing, JvmAbi.DEFAULT_MODULE_NAME)
|
||||||
|
typeMapper.mapAsmMethod(descriptor).descriptor
|
||||||
|
}
|
||||||
|
|
||||||
override fun hasModifier(modifier: UastModifier) = psi.hasModifier(modifier)
|
override fun hasModifier(modifier: UastModifier) = psi.hasModifier(modifier)
|
||||||
override val annotations by lz { psi.getUastAnnotations(this) }
|
override val annotations by lz { psi.getUastAnnotations(this) }
|
||||||
|
|
||||||
@@ -56,6 +69,9 @@ class KotlinConstructorUFunction(
|
|||||||
override val psi: KtConstructor<*>,
|
override val psi: KtConstructor<*>,
|
||||||
override val parent: UElement
|
override val parent: UElement
|
||||||
) : KotlinAbstractUFunction(), PsiElementBacked {
|
) : KotlinAbstractUFunction(), PsiElementBacked {
|
||||||
|
override val name: String
|
||||||
|
get() = "<init>"
|
||||||
|
|
||||||
override val nameElement by lz {
|
override val nameElement by lz {
|
||||||
val constructorKeyword = psi.getConstructorKeyword()?.let { KotlinDumbUElement(it, this) }
|
val constructorKeyword = psi.getConstructorKeyword()?.let { KotlinDumbUElement(it, this) }
|
||||||
constructorKeyword ?: this.getContainingFunction()?.nameElement
|
constructorKeyword ?: this.getContainingFunction()?.nameElement
|
||||||
|
|||||||
Reference in New Issue
Block a user