Update lightclass tests renderer
+mute invalid old light classes tests
This commit is contained in:
@@ -121,7 +121,7 @@ class KtLightAnnotationTest : KotlinLightCodeInsightFixtureTestCase() {
|
||||
myFixture.testHighlighting("Autowired.java", "AnnotatedClass.kt")
|
||||
|
||||
val annotations = myFixture.findClass("AnnotatedClass").fields.single()
|
||||
.expectAnnotations(2).single { it.qualifiedName == "Autowired" }
|
||||
.expectAnnotations(1).single { it.qualifiedName == "Autowired" }
|
||||
val annotationAttributeVal = annotations.findAttributeValue("required") as PsiElement
|
||||
assertTextRangeAndValue("true", true, annotationAttributeVal)
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ package org.jetbrains.kotlin.asJava.classes
|
||||
|
||||
import com.intellij.testFramework.LightProjectDescriptor
|
||||
import org.jetbrains.kotlin.asJava.LightClassGenerationSupport
|
||||
import org.jetbrains.kotlin.asJava.PsiClassRenderer.renderClass
|
||||
import org.jetbrains.kotlin.idea.perf.UltraLightChecker
|
||||
import org.jetbrains.kotlin.idea.perf.UltraLightChecker.checkDescriptorsLeak
|
||||
import org.jetbrains.kotlin.idea.test.KotlinLightCodeInsightFixtureTestCase
|
||||
|
||||
@@ -10,25 +10,21 @@ import com.intellij.openapi.module.Module
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.openapi.util.Conditions
|
||||
import com.intellij.openapi.util.Disposer
|
||||
import com.intellij.psi.*
|
||||
import com.intellij.psi.PsiClass
|
||||
import com.intellij.psi.PsiElement
|
||||
import com.intellij.psi.SyntaxTraverser
|
||||
import com.intellij.psi.search.GlobalSearchScope
|
||||
import com.intellij.psi.util.MethodSignature
|
||||
import com.intellij.testFramework.UsefulTestCase
|
||||
import com.intellij.util.PairProcessor
|
||||
import com.intellij.util.ref.DebugReflectionUtil
|
||||
import junit.framework.TestCase
|
||||
import org.jetbrains.kotlin.asJava.KotlinAsJavaSupport
|
||||
import org.jetbrains.kotlin.asJava.LightClassGenerationSupport
|
||||
import org.jetbrains.kotlin.asJava.PsiClassRenderer.renderClass
|
||||
import org.jetbrains.kotlin.asJava.classes.*
|
||||
import org.jetbrains.kotlin.asJava.elements.KtLightNullabilityAnnotation
|
||||
import org.jetbrains.kotlin.asJava.elements.KtLightPsiArrayInitializerMemberValue
|
||||
import org.jetbrains.kotlin.config.LanguageFeature
|
||||
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
||||
import org.jetbrains.kotlin.idea.caches.resolve.analyze
|
||||
import org.jetbrains.kotlin.idea.core.script.ScriptConfigurationManager
|
||||
import org.jetbrains.kotlin.idea.project.languageVersionSettings
|
||||
import org.jetbrains.kotlin.j2k.getContainingClass
|
||||
import org.jetbrains.kotlin.load.kotlin.NON_EXISTENT_CLASS_NAME
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.psi.KtClassOrObject
|
||||
import org.jetbrains.kotlin.psi.KtFile
|
||||
@@ -131,188 +127,6 @@ object UltraLightChecker {
|
||||
}
|
||||
}
|
||||
|
||||
private fun PsiAnnotation.renderAnnotation(): String {
|
||||
|
||||
val renderedAttributes = parameterList.attributes.map {
|
||||
val attributeValue = it.value?.renderAnnotationMemberValue() ?: "?"
|
||||
|
||||
val name = when {
|
||||
it.name === null && qualifiedName?.startsWith("java.lang.annotation.") == true -> "value"
|
||||
else -> it.name
|
||||
}
|
||||
|
||||
if (name !== null) "$name = $attributeValue" else attributeValue
|
||||
}
|
||||
return "@$qualifiedName(${renderedAttributes.joinToString()})"
|
||||
}
|
||||
|
||||
|
||||
private fun PsiModifierListOwner.renderModifiers(typeIfApplicable: PsiType? = null): String {
|
||||
val annotationsBuffer = mutableListOf<String>()
|
||||
for (annotation in annotations) {
|
||||
if (annotation is KtLightNullabilityAnnotation<*> && skipRenderingNullability(typeIfApplicable)) {
|
||||
continue
|
||||
}
|
||||
|
||||
annotationsBuffer.add(
|
||||
annotation.renderAnnotation() + (if (this is PsiParameter) " " else "\n")
|
||||
)
|
||||
}
|
||||
annotationsBuffer.sort()
|
||||
|
||||
val resultBuffer = StringBuffer(annotationsBuffer.joinToString(separator = ""))
|
||||
for (modifier in PsiModifier.MODIFIERS.filter(::hasModifierProperty)) {
|
||||
resultBuffer.append(modifier).append(" ")
|
||||
}
|
||||
return resultBuffer.toString()
|
||||
}
|
||||
|
||||
private fun PsiModifierListOwner.skipRenderingNullability(typeIfApplicable: PsiType?) =
|
||||
isPrimitiveOrNonExisting(typeIfApplicable) || isPrivateOrParameterInPrivateMethod()
|
||||
|
||||
private val NON_EXISTENT_QUALIFIED_CLASS_NAME = NON_EXISTENT_CLASS_NAME.replace("/", ".")
|
||||
|
||||
private fun isPrimitiveOrNonExisting(typeIfApplicable: PsiType?): Boolean {
|
||||
if (typeIfApplicable is PsiPrimitiveType) return true
|
||||
if (typeIfApplicable?.getCanonicalText(false) == NON_EXISTENT_QUALIFIED_CLASS_NAME) return true
|
||||
|
||||
return typeIfApplicable is PsiPrimitiveType
|
||||
}
|
||||
|
||||
private fun PsiType.renderType() = getCanonicalText(true)
|
||||
|
||||
private fun PsiReferenceList?.renderRefList(keyword: String, sortReferences: Boolean = true): String {
|
||||
if (this == null) return ""
|
||||
|
||||
val references = referencedTypes
|
||||
if (references.isEmpty()) return ""
|
||||
|
||||
val referencesTypes = references.map { it.renderType() }.toTypedArray()
|
||||
|
||||
if (sortReferences) referencesTypes.sort()
|
||||
|
||||
return " " + keyword + " " + referencesTypes.joinToString()
|
||||
}
|
||||
|
||||
private fun PsiVariable.renderVar(): String {
|
||||
var result = this.renderModifiers(type) + type.renderType() + " " + name
|
||||
if (this is PsiParameter && this.isVarArgs) {
|
||||
result += " /* vararg */"
|
||||
}
|
||||
|
||||
if (hasInitializer()) {
|
||||
result += " = ${initializer?.text} /* initializer type: ${initializer?.type?.renderType()} */"
|
||||
}
|
||||
|
||||
computeConstantValue()?.let { result += " /* constant value $it */" }
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
private fun Array<PsiTypeParameter>.renderTypeParams() =
|
||||
if (isEmpty()) ""
|
||||
else "<" + joinToString {
|
||||
val bounds =
|
||||
if (it.extendsListTypes.isNotEmpty())
|
||||
" extends " + it.extendsListTypes.joinToString(" & ", transform = { it.renderType() })
|
||||
else ""
|
||||
it.name!! + bounds
|
||||
} + "> "
|
||||
|
||||
private fun PsiAnnotationMemberValue.renderAnnotationMemberValue(): String = when (this) {
|
||||
is KtLightPsiArrayInitializerMemberValue -> "{${initializers.joinToString { it.renderAnnotationMemberValue() }}}"
|
||||
is PsiAnnotation -> renderAnnotation()
|
||||
else -> text
|
||||
}
|
||||
|
||||
private fun PsiMethod.renderMethod() =
|
||||
renderModifiers(returnType) +
|
||||
(if (isVarArgs) "/* vararg */ " else "") +
|
||||
typeParameters.renderTypeParams() +
|
||||
(returnType?.renderType() ?: "") + " " +
|
||||
name +
|
||||
"(" + parameterList.parameters.joinToString { it.renderModifiers(it.type) + it.type.renderType() } + ")" +
|
||||
(this as? PsiAnnotationMethod)?.defaultValue?.let { " default " + it.renderAnnotationMemberValue() }.orEmpty() +
|
||||
throwsList.referencedTypes.let { thrownTypes ->
|
||||
if (thrownTypes.isEmpty()) ""
|
||||
else " throws " + thrownTypes.joinToString { it.renderType() }
|
||||
} +
|
||||
";" +
|
||||
"// ${getSignature(PsiSubstitutor.EMPTY).renderSignature()}"
|
||||
|
||||
private fun MethodSignature.renderSignature(): String {
|
||||
val typeParams = typeParameters.renderTypeParams()
|
||||
val paramTypes = parameterTypes.joinToString(prefix = "(", postfix = ")") { it.renderType() }
|
||||
val name = if (isConstructor) ".ctor" else name
|
||||
return "$typeParams $name$paramTypes"
|
||||
}
|
||||
|
||||
private fun PsiEnumConstant.renderEnumConstant(): String {
|
||||
val initializingClass = initializingClass ?: return name
|
||||
|
||||
return buildString {
|
||||
appendLine("$name {")
|
||||
append(initializingClass.renderMembers())
|
||||
append("}")
|
||||
}
|
||||
}
|
||||
|
||||
fun PsiClass.renderClass(): String {
|
||||
val classWord = when {
|
||||
isAnnotationType -> "@interface"
|
||||
isInterface -> "interface"
|
||||
isEnum -> "enum"
|
||||
else -> "class"
|
||||
}
|
||||
|
||||
return buildString {
|
||||
append(renderModifiers())
|
||||
append("$classWord ")
|
||||
append("$name /* $qualifiedName*/")
|
||||
append(typeParameters.renderTypeParams())
|
||||
append(extendsList.renderRefList("extends"))
|
||||
append(implementsList.renderRefList("implements"))
|
||||
appendLine(" {")
|
||||
|
||||
if (isEnum) {
|
||||
append(
|
||||
fields
|
||||
.filterIsInstance<PsiEnumConstant>()
|
||||
.joinToString(",\n") { it.renderEnumConstant() }.prependDefaultIndent()
|
||||
)
|
||||
append(";\n\n")
|
||||
}
|
||||
|
||||
append(renderMembers())
|
||||
append("}")
|
||||
}
|
||||
}
|
||||
|
||||
private fun PsiClass.renderMembers(): String {
|
||||
return buildString {
|
||||
appendSorted(
|
||||
fields
|
||||
.filterNot { it is PsiEnumConstant }
|
||||
.map { it.renderVar().prependDefaultIndent() + ";\n\n" }
|
||||
)
|
||||
|
||||
appendSorted(
|
||||
methods
|
||||
.map { it.renderMethod().prependDefaultIndent() + "\n\n" }
|
||||
)
|
||||
|
||||
appendSorted(
|
||||
innerClasses.map { "class ${it.name} ...\n\n".prependDefaultIndent() }
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun StringBuilder.appendSorted(list: List<String>) {
|
||||
append(list.sorted().joinToString(""))
|
||||
}
|
||||
|
||||
private fun String.prependDefaultIndent() = prependIndent(" ")
|
||||
|
||||
private fun checkDescriptorLeakOnElement(element: PsiElement) {
|
||||
DebugReflectionUtil.walkObjects(
|
||||
10,
|
||||
|
||||
Reference in New Issue
Block a user