Uast: support internal class names in Java and method signatures in Java and Kotlin
This commit is contained in:
@@ -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(
|
||||
|
||||
@@ -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<UFunction> {
|
||||
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
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user