FIR: Add test for total kotlin resolve #KT-24077 Fixed

This commit is contained in:
Simon Ogorodnik
2018-11-23 19:09:28 +03:00
committed by Mikhail Glukhikh
parent 619bddfdbc
commit dcd41bd26f
3 changed files with 200 additions and 1 deletions
@@ -10,7 +10,7 @@ import org.jetbrains.kotlin.fir.visitors.FirTransformer
class FirTotalResolveTransformer {
private val transformers: List<FirTransformer<Nothing?>> = listOf(
val transformers: List<FirTransformer<Nothing?>> = listOf(
FirImportResolveTransformer(),
FirTypeResolveTransformer(),
FirStatusResolveTransformer()
@@ -0,0 +1,82 @@
/*
* Copyright 2010-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.fir
import com.intellij.psi.search.ProjectScope
import com.intellij.testFramework.TestDataPath
import org.jetbrains.kotlin.cli.jvm.compiler.EnvironmentConfigFiles
import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment
import org.jetbrains.kotlin.fir.builder.RawFirBuilder
import org.jetbrains.kotlin.fir.resolve.FirProvider
import org.jetbrains.kotlin.fir.resolve.impl.FirProviderImpl
import org.jetbrains.kotlin.fir.resolve.transformers.FirTotalResolveTransformer
import org.jetbrains.kotlin.test.ConfigurationKind
import org.jetbrains.kotlin.test.KotlinTestUtils
import org.jetbrains.kotlin.test.TestJdkKind
import java.io.File
@TestDataPath("/")
class FirResolveTestTotalKotlin : AbstractFirResolveWithSessionTestCase() {
private val forbiddenDirectories = listOf("testdata", "resources")
override fun createEnvironment(): KotlinCoreEnvironment {
val configurationKind = ConfigurationKind.ALL
val testJdkKind = TestJdkKind.FULL_JDK
val javaFiles = File(".").walkTopDown().onEnter {
it.name.toLowerCase() !in forbiddenDirectories
}.filter {
it.isDirectory
}.mapNotNull { dir ->
if (dir.name in setOf("src", "test", "tests")) {
if (dir.walkTopDown().any { it.extension == "java" }) {
return@mapNotNull dir
}
}
null
}.toList()
val configuration = KotlinTestUtils.newConfiguration(configurationKind, testJdkKind, emptyList(), javaFiles)
return KotlinCoreEnvironment.createForTests(testRootDisposable, configuration, EnvironmentConfigFiles.JVM_CONFIG_FILES)
}
fun testTotalKotlin() {
val testDataPath = "."
val root = File(testDataPath)
println("BASE PATH: ${root.absolutePath}")
val allFiles = root.walkTopDown().filter { file ->
!file.isDirectory && forbiddenDirectories.none { it in file.path.toLowerCase() } && file.extension == "kt"
}
val ktFiles = allFiles.map {
val text = KotlinTestUtils.doLoadFile(it)
KotlinTestUtils.createFile(it.path, text, project)
}
val scope = ProjectScope.getContentScope(project)
val session = createSession(scope)
val builder = RawFirBuilder(session)
val totalTransformer = FirTotalResolveTransformer()
val firFiles = ktFiles.map {
val firFile = builder.buildFirFile(it)
(session.service<FirProvider>() as FirProviderImpl).recordFile(firFile)
firFile
}.toList()
println("Raw FIR up, files: ${firFiles.size}")
doFirResolveTestBench(firFiles, totalTransformer.transformers)
}
}
@@ -0,0 +1,117 @@
/*
* Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.fir
import com.intellij.openapi.fileEditor.FileDocumentManager
import org.jetbrains.kotlin.fir.declarations.FirFile
import org.jetbrains.kotlin.fir.types.ConeClassErrorType
import org.jetbrains.kotlin.fir.types.ConeKotlinErrorType
import org.jetbrains.kotlin.fir.types.FirResolvedType
import org.jetbrains.kotlin.fir.types.FirType
import org.jetbrains.kotlin.fir.visitors.FirTransformer
import org.jetbrains.kotlin.fir.visitors.FirVisitorVoid
import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.psi.psiUtil.startOffset
import kotlin.reflect.KClass
import kotlin.system.measureNanoTime
fun doFirResolveTestBench(firFiles: List<FirFile>, transformers: List<FirTransformer<Nothing?>>) {
System.gc()
val timePerTransformer = mutableMapOf<KClass<*>, Long>()
val counterPerTransformer = mutableMapOf<KClass<*>, Long>()
val totalLength = 0
var resolvedTypes = 0
var errorTypes = 0
var unresolvedTypes = 0
try {
for (transformer in transformers) {
for (firFile in firFiles) {
val time = measureNanoTime {
try {
transformer.transformFile(firFile, null)
} catch (e: Throwable) {
val ktFile = firFile.psi as KtFile
println("Fail in file: ${ktFile.virtualFilePath}")
println(ktFile.text)
throw e
}
}
timePerTransformer.merge(transformer::class, time) { a, b -> a + b }
counterPerTransformer.merge(transformer::class, 1) { a, b -> a + b }
//totalLength += StringBuilder().apply { FirRenderer(this).visitFile(firFile) }.length
}
}
println("SUCCESS!")
} finally {
var implicitTypes = 0
val errorTypesReports = mutableMapOf<String, String>()
val fileDocumentManager = FileDocumentManager.getInstance()
firFiles.forEach {
it.accept(object : FirVisitorVoid() {
override fun visitElement(element: FirElement) {
element.acceptChildren(this)
}
override fun visitType(type: FirType) {
unresolvedTypes++
}
override fun visitResolvedType(resolvedType: FirResolvedType) {
resolvedTypes++
val type = resolvedType.type
if (type is ConeKotlinErrorType || type is ConeClassErrorType) {
if (resolvedType.psi == null) {
implicitTypes++
} else {
val psi = resolvedType.psi!!
val problem = "$type with psi `${psi.text}`"
val document = try {
fileDocumentManager.getDocument(psi.containingFile.virtualFile)
} catch (t: Throwable) {
throw Exception("for file ${psi.containingFile}", t)
}
val line = document?.getLineNumber(psi.startOffset) ?: 0
val char = psi.startOffset - (document?.getLineStartOffset(line) ?: 0)
val report = "e: ${psi.containingFile?.virtualFile?.path}: ($line:$char): $problem"
errorTypesReports[problem] = report
errorTypes++
}
}
}
})
}
errorTypesReports.forEach {
println(it.value)
}
println("TOTAL LENGTH: $totalLength")
println("UNRESOLVED TYPES: $unresolvedTypes")
println("RESOLVED TYPES: $resolvedTypes")
println("GOOD TYPES: ${resolvedTypes - errorTypes}")
println("ERROR TYPES: $errorTypes")
println("IMPLICIT TYPES: $implicitTypes")
println("UNIQUE ERROR TYPES: ${errorTypesReports.size}")
timePerTransformer.forEach { (transformer, time) ->
val counter = counterPerTransformer[transformer]!!
println("${transformer.simpleName}, TIME: ${time * 1e-6} ms, TIME PER FILE: ${(time / counter) * 1e-6} ms, FILES: $counter")
}
}
}