From dcd41bd26f45ec460cf3f80ee3dab03926d235b5 Mon Sep 17 00:00:00 2001 From: Simon Ogorodnik Date: Fri, 23 Nov 2018 19:09:28 +0300 Subject: [PATCH] FIR: Add test for total kotlin resolve #KT-24077 Fixed --- .../FirTotalResolveTransformer.kt | 2 +- .../kotlin/fir/FirResolveTestTotalKotlin.kt | 82 ++++++++++++ .../jetbrains/kotlin/fir/FirResolveBench.kt | 117 ++++++++++++++++++ 3 files changed, 200 insertions(+), 1 deletion(-) create mode 100644 compiler/fir/resolve/tests/org/jetbrains/kotlin/fir/FirResolveTestTotalKotlin.kt create mode 100644 compiler/tests-common/tests/org/jetbrains/kotlin/fir/FirResolveBench.kt diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/FirTotalResolveTransformer.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/FirTotalResolveTransformer.kt index 70f21910e3f..619a9c2c05b 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/FirTotalResolveTransformer.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/FirTotalResolveTransformer.kt @@ -10,7 +10,7 @@ import org.jetbrains.kotlin.fir.visitors.FirTransformer class FirTotalResolveTransformer { - private val transformers: List> = listOf( + val transformers: List> = listOf( FirImportResolveTransformer(), FirTypeResolveTransformer(), FirStatusResolveTransformer() diff --git a/compiler/fir/resolve/tests/org/jetbrains/kotlin/fir/FirResolveTestTotalKotlin.kt b/compiler/fir/resolve/tests/org/jetbrains/kotlin/fir/FirResolveTestTotalKotlin.kt new file mode 100644 index 00000000000..bd7ebaba35a --- /dev/null +++ b/compiler/fir/resolve/tests/org/jetbrains/kotlin/fir/FirResolveTestTotalKotlin.kt @@ -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() as FirProviderImpl).recordFile(firFile) + firFile + }.toList() + + + println("Raw FIR up, files: ${firFiles.size}") + + doFirResolveTestBench(firFiles, totalTransformer.transformers) + } +} \ No newline at end of file diff --git a/compiler/tests-common/tests/org/jetbrains/kotlin/fir/FirResolveBench.kt b/compiler/tests-common/tests/org/jetbrains/kotlin/fir/FirResolveBench.kt new file mode 100644 index 00000000000..d1dd477e386 --- /dev/null +++ b/compiler/tests-common/tests/org/jetbrains/kotlin/fir/FirResolveBench.kt @@ -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, transformers: List>) { + + System.gc() + + val timePerTransformer = mutableMapOf, Long>() + val counterPerTransformer = mutableMapOf, 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() + + 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") + } + } +} \ No newline at end of file