[FIR IDE] Add Fir lightclasses tests and fix FindUsages tests

This commit is contained in:
Igor Yakovlev
2020-10-07 16:36:16 +03:00
committed by Ilya Kirillov
parent 3cefef03ff
commit dbb54c87bc
213 changed files with 3496 additions and 218 deletions
@@ -10,51 +10,40 @@ import org.jetbrains.kotlin.asJava.LightClassGenerationSupport
import org.jetbrains.kotlin.asJava.PsiClassRenderer
import org.jetbrains.kotlin.asJava.PsiClassRenderer.renderClass
import org.jetbrains.kotlin.idea.perf.UltraLightChecker
import org.jetbrains.kotlin.idea.perf.UltraLightChecker.checkByJavaFile
import org.jetbrains.kotlin.idea.perf.UltraLightChecker.checkDescriptorsLeak
import org.jetbrains.kotlin.idea.test.KotlinLightCodeInsightFixtureTestCase
import org.jetbrains.kotlin.idea.test.KotlinWithJdkAndRuntimeLightProjectDescriptor
import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.test.InTextDirectivesUtils
import org.jetbrains.kotlin.test.KotlinTestUtils
import java.io.File
abstract class AbstractUltraLightClassLoadingTest : KotlinLightCodeInsightFixtureTestCase() {
override fun getProjectDescriptor(): LightProjectDescriptor = KotlinWithJdkAndRuntimeLightProjectDescriptor.INSTANCE
fun doTest(testDataPath: String) {
open fun doTest(testDataPath: String) {
val sourceText = File(testDataPath).readText()
val file = myFixture.addFileToProject(testDataPath, sourceText) as KtFile
UltraLightChecker.checkForReleaseCoroutine(sourceText, module)
val expectedTextFile = File(testDataPath.replaceFirst("\\.kt\$".toRegex(), ".java"))
if (expectedTextFile.exists()) {
val renderedResult =
UltraLightChecker.allClasses(file).mapNotNull { ktClass ->
LightClassGenerationSupport.getInstance(ktClass.project).createUltraLightClass(ktClass)?.let { it to ktClass }
}.joinToString("\n\n") { (ultraLightClass, ktClass) ->
with(UltraLightChecker) {
val extendedTypeRendererOld = PsiClassRenderer.extendedTypeRenderer
try {
PsiClassRenderer.extendedTypeRenderer = file.name == "typeAnnotations.kt"
ultraLightClass.renderClass()
} finally {
PsiClassRenderer.extendedTypeRenderer = extendedTypeRendererOld
}.also {
checkDescriptorsLeak(ultraLightClass)
}
}
val checkByJavaFile = InTextDirectivesUtils.isDirectiveDefined(sourceText, "CHECK_BY_JAVA_FILE")
val ktClassOrObjects = UltraLightChecker.allClasses(file)
if (checkByJavaFile) {
val classFabric = LightClassGenerationSupport.getInstance(project)
val classList = ktClassOrObjects.mapNotNull { classFabric.createUltraLightClass(it) }
checkByJavaFile(testDataPath, classList)
classList.forEach { checkDescriptorsLeak(it) }
} else {
for (ktClass in ktClassOrObjects) {
val ultraLightClass = UltraLightChecker.checkClassEquivalence(ktClass)
if (ultraLightClass != null) {
checkDescriptorsLeak(ultraLightClass)
}
KotlinTestUtils.assertEqualsToFile(expectedTextFile, renderedResult)
return
}
for (ktClass in UltraLightChecker.allClasses(file)) {
val ultraLightClass = UltraLightChecker.checkClassEquivalence(ktClass)
if (ultraLightClass != null) {
checkDescriptorsLeak(ultraLightClass)
}
}
}
}
@@ -18,7 +18,7 @@ import java.io.File
abstract class AbstractUltraLightFacadeClassTest : KotlinLightCodeInsightFixtureTestCase() {
override fun getProjectDescriptor(): LightProjectDescriptor = KotlinWithJdkAndRuntimeLightProjectDescriptor.INSTANCE
fun doTest(testDataPath: String) {
open fun doTest(testDataPath: String) {
val sourceText = File(testDataPath).readText()
myFixture.addFileToProject(testDataPath, sourceText) as KtFile
@@ -32,6 +32,10 @@ abstract class AbstractUltraLightFacadeClassTest : KotlinLightCodeInsightFixture
val scope = GlobalSearchScope.allScope(project)
val facades = KotlinAsJavaSupport.getInstance(project).getFacadeNames(FqName.ROOT, scope)
checkLightFacades(testDataPath, facades, scope)
}
protected open fun checkLightFacades(testDataPath: String, facades: Collection<String>, scope: GlobalSearchScope) {
for (facadeName in facades) {
val ultraLightClass = UltraLightChecker.checkFacadeEquivalence(FqName(facadeName), scope, project)
if (ultraLightClass != null) {
@@ -49,6 +49,6 @@ abstract class AbstractFindUsagesMultiModuleTest : AbstractMultiModuleTest() {
UsefulTestCase.assertInstanceOf(caretElement!!, caretElementClass)
val options = parser?.parse(mainFileText, project)
findUsagesAndCheckResults(mainFileText, prefix, rootPath, caretElement, options, project, alwaysAppendFileName = true)
findUsagesAndCheckResults(mainFileText, prefix, rootPath, caretElement, options, project, alwaysAppendFileName = true, isFirPlugin = isFirPlugin)
}
}
@@ -194,14 +194,41 @@ abstract class AbstractFindUsagesTest : KotlinLightCodeInsightFixtureTestCase()
val prefixForCheck = prefix + prefixForResults
if (isLibraryElement) {
val originalElement = caretElement.originalElement
findUsagesAndCheckResults(mainFileText, prefixForCheck, rootPath, originalElement, options, project)
findUsagesAndCheckResults(
mainFileText,
prefixForCheck,
rootPath,
originalElement,
options,
project,
alwaysAppendFileName = false,
isFirPlugin = isFirPlugin
)
val navigationElement = caretElement.navigationElement
if (navigationElement !== originalElement) {
findUsagesAndCheckResults(mainFileText, prefixForCheck, rootPath, navigationElement, options, project)
findUsagesAndCheckResults(
mainFileText,
prefixForCheck,
rootPath,
navigationElement,
options,
project,
alwaysAppendFileName = false,
isFirPlugin = isFirPlugin
)
}
} else {
findUsagesAndCheckResults(mainFileText, prefixForCheck, rootPath, caretElement, options, project)
findUsagesAndCheckResults(
mainFileText,
prefixForCheck,
rootPath,
caretElement,
options,
project,
alwaysAppendFileName = false,
isFirPlugin = isFirPlugin
)
}
} finally {
fixtureClasses.forEach { TestFixtureExtension.unloadFixture(it) }
@@ -259,7 +286,8 @@ internal fun <T : PsiElement> findUsagesAndCheckResults(
caretElement: T,
options: FindUsagesOptions?,
project: Project,
alwaysAppendFileName: Boolean = false
alwaysAppendFileName: Boolean = false,
isFirPlugin: Boolean = false
) {
val highlightingMode = InTextDirectivesUtils.isDirectiveDefined(mainFileText, "// HIGHLIGHTING")
@@ -277,7 +305,7 @@ internal fun <T : PsiElement> findUsagesAndCheckResults(
val searchSuperDeclaration =
InTextDirectivesUtils.findLinesWithPrefixesRemoved(mainFileText, "$CHECK_SUPER_METHODS_YES_NO_DIALOG:").firstOrNull() != "no"
findUsages(caretElement, options, highlightingMode, project, searchSuperDeclaration)
findUsages(caretElement, options, highlightingMode, project, searchSuperDeclaration, isFirPlugin)
} finally {
ExpressionsOfTypeProcessor.testLog = null
if (logList.size > 0) {
@@ -332,7 +360,16 @@ internal fun <T : PsiElement> findUsagesAndCheckResults(
try {
ExpressionsOfTypeProcessor.mode = ExpressionsOfTypeProcessor.Mode.ALWAYS_PLAIN
findUsagesAndCheckResults(mainFileText, prefix, rootPath, caretElement, options, project)
findUsagesAndCheckResults(
mainFileText,
prefix,
rootPath,
caretElement,
options,
project,
alwaysAppendFileName = false,
isFirPlugin = isFirPlugin
)
} finally {
ExpressionsOfTypeProcessor.mode = ExpressionsOfTypeProcessor.Mode.ALWAYS_SMART
}
@@ -344,7 +381,8 @@ internal fun findUsages(
options: FindUsagesOptions?,
highlightingMode: Boolean,
project: Project,
searchSuperDeclaration: Boolean = true
searchSuperDeclaration: Boolean = true,
isFirPlugin: Boolean = false
): Collection<UsageInfo> {
try {
val handler: FindUsagesHandler = if (targetElement is PsiMember)
@@ -367,9 +405,23 @@ internal fun findUsages(
val processor = CommonProcessors.CollectProcessor<UsageInfo>()
for (psiElement in handler.primaryElements + handler.secondaryElements) {
if (highlightingMode) {
project.runReadActionInSmartMode {
for (reference in handler.findReferencesToHighlight(psiElement, options.searchScope)) {
processor.process(UsageInfo(reference))
if (isFirPlugin) {
ProgressManager.getInstance().run(
object : Task.Modal(project, "", false) {
override fun run(indicator: ProgressIndicator) {
project.runReadActionInSmartMode {
for (reference in handler.findReferencesToHighlight(psiElement, options.searchScope)) {
processor.process(UsageInfo(reference))
}
}
}
},
)
} else {
project.runReadActionInSmartMode {
for (reference in handler.findReferencesToHighlight(psiElement, options.searchScope)) {
processor.process(UsageInfo(reference))
}
}
}
} else {
@@ -128,8 +128,7 @@ abstract class AbstractIdeCompiledLightClassTest : KotlinDaemonAnalyzerTestCase(
}
private fun testLightClass(expected: File, testData: File, normalize: (String) -> String, findLightClass: (String) -> PsiClass?) {
LightClassTestCommon.testLightClass(
expected,
val actual = LightClassTestCommon.getActualLightClassText(
testData,
findLightClass = findLightClass,
normalizeText = { text ->
@@ -144,9 +143,10 @@ private fun testLightClass(expected: File, testData: File, normalize: (String) -
.run(normalize)
}
)
KotlinTestUtils.assertEqualsToFile(expected, actual)
}
private fun findClass(fqName: String, ktFile: KtFile?, project: Project): PsiClass? {
fun findClass(fqName: String, ktFile: KtFile?, project: Project): PsiClass? {
ktFile?.script?.let {
return it.toLightClass()
}
@@ -20,16 +20,20 @@ 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
import org.jetbrains.kotlin.asJava.PsiClassRenderer.renderClass
import org.jetbrains.kotlin.asJava.classes.*
import org.jetbrains.kotlin.config.LanguageFeature
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
import org.jetbrains.kotlin.idea.project.languageVersionSettings
import org.jetbrains.kotlin.idea.test.KotlinLightCodeInsightFixtureTestCaseBase
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.psi.KtClassOrObject
import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.psi.KtScript
import org.jetbrains.kotlin.test.KotlinTestUtils
import org.junit.Assert
import java.io.File
import kotlin.test.assertFails
fun UsefulTestCase.forceUsingOldLightClassesForTest() {
@@ -76,6 +80,29 @@ object UltraLightChecker {
return ultraLightClass
}
fun checkByJavaFile(testDataPath: String, lightClasses: List<KtLightClass>) {
val expectedTextFile = getJavaFileForTest(testDataPath)
val renderedResult = renderLightClasses(testDataPath, lightClasses)
KotlinTestUtils.assertEqualsToFile(expectedTextFile, renderedResult)
}
fun getJavaFileForTest(testDataPath: String): File {
val expectedTextFile = KotlinTestUtils.replaceExtension(File(testDataPath), "java")
KotlinLightCodeInsightFixtureTestCaseBase.assertTrue(expectedTextFile.exists())
return expectedTextFile
}
fun renderLightClasses(testDataPath: String, lightClasses: List<KtLightClass>): String {
val extendedTypeRendererOld = PsiClassRenderer.extendedTypeRenderer
return try {
PsiClassRenderer.extendedTypeRenderer = testDataPath.endsWith("typeAnnotations.kt")
lightClasses.joinToString("\n\n") { it.renderClass() }
} finally {
PsiClassRenderer.extendedTypeRenderer = extendedTypeRendererOld
}
}
fun checkClassEquivalence(ktClass: KtClassOrObject): KtUltraLightClass? {
val gold = KtLightClassForSourceDeclaration.createNoCache(ktClass, forceUsingOldLightClasses = true)
val ultraLightClass = LightClassGenerationSupport.getInstance(ktClass.project).createUltraLightClass(ktClass) ?: return null