Update lightclass tests renderer

+mute invalid old light classes tests
This commit is contained in:
Igor Yakovlev
2020-05-20 13:49:24 +03:00
parent c70383cc70
commit 309bf49a83
140 changed files with 1314 additions and 1191 deletions
@@ -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,