diff --git a/plugins/uast-common/src/org/jetbrains/uast/declarations/UClass.kt b/plugins/uast-common/src/org/jetbrains/uast/declarations/UClass.kt index a92fdbd226e..9ee25e52440 100644 --- a/plugins/uast-common/src/org/jetbrains/uast/declarations/UClass.kt +++ b/plugins/uast-common/src/org/jetbrains/uast/declarations/UClass.kt @@ -28,7 +28,8 @@ interface UClass : UDeclaration, UFqNamed, UModifierOwner, UAnnotated { val companions: List - val internalName: String? + open val internalName: String? + get() = null val superTypes: List val declarations: List diff --git a/plugins/uast-common/src/org/jetbrains/uast/declarations/UFunction.kt b/plugins/uast-common/src/org/jetbrains/uast/declarations/UFunction.kt index 3ba6f805dd0..ecdd243ceb0 100644 --- a/plugins/uast-common/src/org/jetbrains/uast/declarations/UFunction.kt +++ b/plugins/uast-common/src/org/jetbrains/uast/declarations/UFunction.kt @@ -25,6 +25,9 @@ interface UFunction : UDeclaration, UModifierOwner, UAnnotated { val body: UExpression val visibility: UastVisibility + open val bytecodeDescriptor: String? + get() = null + fun getSuperFunctions(context: UastContext): List override fun traverse(handler: UastHandler) { diff --git a/plugins/uast-java/src/org/jetbrains/uast/java/declarations/JavaUClass.kt b/plugins/uast-java/src/org/jetbrains/uast/java/declarations/JavaUClass.kt index 0d57385bd17..633066b2fff 100644 --- a/plugins/uast-java/src/org/jetbrains/uast/java/declarations/JavaUClass.kt +++ b/plugins/uast-java/src/org/jetbrains/uast/java/declarations/JavaUClass.kt @@ -15,7 +15,10 @@ */ package org.jetbrains.uast.java +import com.intellij.ide.util.JavaAnonymousClassesHelper import com.intellij.psi.* +import com.intellij.psi.util.ClassUtil +import com.intellij.psi.util.PsiTreeUtil import com.intellij.psi.util.PsiTypesUtil import org.jetbrains.uast.* import org.jetbrains.uast.kinds.UastClassKind @@ -59,7 +62,7 @@ class JavaUClass( override val isAnonymous: Boolean get() = psi is PsiAnonymousClass - override val internalName = null + override val internalName by lz { getInternalName(psi) } override val superTypes by lz { psi.extendsListTypes.map { JavaConverter.convert(it, this) } + psi.implementsListTypes.map { JavaConverter.convert(it, this) } @@ -98,6 +101,61 @@ class JavaUClass( 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( diff --git a/plugins/uast-java/src/org/jetbrains/uast/java/declarations/JavaUFunction.kt b/plugins/uast-java/src/org/jetbrains/uast/java/declarations/JavaUFunction.kt index 88627c79bbe..a6580b10589 100644 --- a/plugins/uast-java/src/org/jetbrains/uast/java/declarations/JavaUFunction.kt +++ b/plugins/uast-java/src/org/jetbrains/uast/java/declarations/JavaUFunction.kt @@ -15,7 +15,10 @@ */ package org.jetbrains.uast.java +import com.intellij.psi.PsiArrayType +import com.intellij.psi.PsiClassType import com.intellij.psi.PsiMethod +import com.intellij.psi.PsiType import org.jetbrains.uast.* import org.jetbrains.uast.psi.PsiElementBacked @@ -53,10 +56,37 @@ class JavaUFunction( override val visibility: UastVisibility get() = psi.getVisibility() - + override val body by lz { JavaConverter.convertOrEmpty(psi.body, this) } + override val bytecodeDescriptor by lz { getDescriptor(psi) } + override fun getSuperFunctions(context: UastContext): List { 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 + } + } } \ No newline at end of file diff --git a/plugins/uast-kotlin/src/org/jetbrains/kotlin/uast/declarations/kotlinUFunctions.kt b/plugins/uast-kotlin/src/org/jetbrains/kotlin/uast/declarations/kotlinUFunctions.kt index 9d426e4f622..6963224ad23 100644 --- a/plugins/uast-kotlin/src/org/jetbrains/kotlin/uast/declarations/kotlinUFunctions.kt +++ b/plugins/uast-kotlin/src/org/jetbrains/kotlin/uast/declarations/kotlinUFunctions.kt @@ -16,11 +16,16 @@ 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.FunctionDescriptor +import org.jetbrains.kotlin.fileClasses.NoResolveFileClassesProvider import org.jetbrains.kotlin.idea.caches.resolve.analyze import org.jetbrains.kotlin.idea.caches.resolve.resolveToDescriptorIfAny import org.jetbrains.kotlin.lexer.KtTokens +import org.jetbrains.kotlin.load.java.JvmAbi import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.resolve.BindingContext import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode @@ -45,6 +50,14 @@ abstract class KotlinAbstractUFunction : KotlinAbstractUElement(), UFunction, Ps }.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 val annotations by lz { psi.getUastAnnotations(this) } @@ -56,6 +69,9 @@ class KotlinConstructorUFunction( override val psi: KtConstructor<*>, override val parent: UElement ) : KotlinAbstractUFunction(), PsiElementBacked { + override val name: String + get() = "" + override val nameElement by lz { val constructorKeyword = psi.getConstructorKeyword()?.let { KotlinDumbUElement(it, this) } constructorKeyword ?: this.getContainingFunction()?.nameElement