Analysis LC: introduce Symbol LC tests

This commit is contained in:
Ilya Kirillov
2021-12-22 13:45:53 +03:00
parent abf7a4c5ac
commit 40fdb26569
34 changed files with 817 additions and 56 deletions
@@ -33,8 +33,8 @@ import org.junit.jupiter.api.BeforeEach
import org.junit.jupiter.api.TestInfo
import java.nio.file.Path
import java.nio.file.Paths
import kotlin.io.path.exists
import java.util.concurrent.ExecutionException
import kotlin.io.path.exists
import kotlin.io.path.nameWithoutExtension
interface FrontendApiTestConfiguratorService {
@@ -56,7 +56,7 @@ interface FrontendApiTestConfiguratorService {
fun doOutOfBlockModification(file: KtFile)
fun preprocessTestDataPath(path: Path) : Path = path
fun preprocessTestDataPath(path: Path): Path = path
}
abstract class AbstractFrontendApiTest(val configurator: FrontendApiTestConfiguratorService) : TestWithDisposable() {
@@ -99,7 +99,7 @@ abstract class AbstractFrontendApiTest(val configurator: FrontendApiTestConfigur
}
}
private fun getTestDataFileSiblingPath(extension: String, testPrefix: String?): Path {
protected fun getTestDataFileSiblingPath(extension: String, testPrefix: String?): Path {
val extensionWithDot = "." + extension.removePrefix(".")
val baseName = testDataPath.nameWithoutExtension
@@ -139,6 +139,13 @@ abstract class AbstractFrontendApiTest(val configurator: FrontendApiTestConfigur
this.testInfo = this@AbstractFrontendApiTest.testInfo
}
protected open fun handleInitializationError(exception: Throwable, moduleStructure: TestModuleStructure): InitializationErrorAction =
InitializationErrorAction.THROW
enum class InitializationErrorAction {
IGNORE, THROW
}
protected fun runTest(@TestDataFile path: String) {
testDataPath = configurator.preprocessTestDataPath(Paths.get(path))
val testConfiguration = testConfiguration(path, configure)
@@ -147,26 +154,36 @@ abstract class AbstractFrontendApiTest(val configurator: FrontendApiTestConfigur
val moduleStructure = testConfiguration.moduleStructureExtractor.splitTestDataByModules(
path,
testConfiguration.directives,
).also { testModuleStructure ->
testConfiguration.testServices.register(TestModuleStructure::class, testModuleStructure)
testConfiguration.preAnalysisHandlers.forEach { preprocessor ->
preprocessor.preprocessModuleStructure(testModuleStructure)
}
}
)
val singleModule = moduleStructure.modules.single()
val project = testServices.compilerConfigurationProvider.getProject(singleModule)
val moduleInfoProvider = testServices.projectModuleProvider
val moduleInfo = moduleInfoProvider.getModule(singleModule.name)
with(project as MockProject) {
configurator.registerProjectServices(this)
}
registerApplicationServices()
testConfiguration.testServices.register(TestModuleStructure::class, moduleStructure)
testConfiguration.preAnalysisHandlers.forEach { preprocessor ->
try {
preprocessor.preprocessModuleStructure(moduleStructure)
} catch (exception: Throwable) {
when (handleInitializationError(exception, moduleStructure)) {
InitializationErrorAction.IGNORE -> {}
InitializationErrorAction.THROW -> throw exception
}
}
}
val moduleInfo = moduleInfoProvider.getModule(singleModule.name)
val ktFiles = when (moduleInfo) {
is TestKtSourceModule -> moduleInfo.testFilesToKtFiles.filterKeys { testFile -> !testFile.isAdditional }.values.toList()
is TestKtLibraryModule -> moduleInfo.ktFiles.toList()
else -> error("Unexpected $moduleInfo")
}
val ktFiles = moduleInfo.testFilesToKtFiles.filterKeys { testFile -> !testFile.isAdditional }.values.toList()
configurator.prepareTestFiles(ktFiles, singleModule, testServices)
doTestByFileStructure(ktFiles, moduleStructure, testServices)
if (!enableTestInDependedMode || ktFiles.any {
@@ -5,9 +5,7 @@
package org.jetbrains.kotlin.analysis.api.impl.barebone.test
import com.intellij.openapi.project.Project
import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.test.model.TestFile
import org.jetbrains.kotlin.test.model.TestModule
import org.jetbrains.kotlin.test.services.TestService
import org.jetbrains.kotlin.test.services.TestServices
@@ -15,18 +13,18 @@ import org.jetbrains.kotlin.test.services.TestServices
class TestKtModuleProvider(
private val testServices: TestServices
) : TestService {
private val cache = mutableMapOf<String, TestKtSourceModule>()
private val cache = mutableMapOf<String, TestKtModule>()
fun registerModuleInfo(project: Project, testModule: TestModule, ktFiles: Map<TestFile, KtFile>) {
cache[testModule.name] = TestKtSourceModule(project, testModule, ktFiles, testServices)
fun registerModuleInfo(testModule: TestModule, ktModule: TestKtModule) {
cache[testModule.name] = ktModule
}
fun getModuleInfoByKtFile(ktFile: KtFile): TestKtSourceModule =
fun getModuleInfoByKtFile(ktFile: KtFile): TestKtModule =
cache.values.first { moduleSourceInfo ->
(if (ktFile.isPhysical) ktFile else ktFile.originalFile) in moduleSourceInfo.ktFiles
}
fun getModule(moduleName: String): TestKtSourceModule =
fun getModule(moduleName: String): TestKtModule =
cache.getValue(moduleName)
}
@@ -31,24 +31,23 @@ import java.nio.file.Path
import java.nio.file.Paths
@OptIn(ExperimentalStdlibApi::class)
class TestKtSourceModule(
override val project: Project,
abstract class TestKtModule(
val project: Project,
val testModule: TestModule,
val testFilesToKtFiles: Map<TestFile, KtFile>,
val ktFiles: Set<KtFile>,
testServices: TestServices,
) : KtSourceModule {
) {
private val moduleProvider = testServices.projectModuleProvider
private val compilerConfigurationProvider = testServices.compilerConfigurationProvider
private val configuration = compilerConfigurationProvider.getCompilerConfiguration(testModule)
val ktFiles = testFilesToKtFiles.values.toSet()
override val moduleName: String
val moduleName: String
get() = testModule.name
override val directRegularDependencies: List<KtModule> by lazy(LazyThreadSafetyMode.PUBLICATION) {
val directRegularDependencies: List<KtModule> by lazy(LazyThreadSafetyMode.PUBLICATION) {
buildList {
testModule.allDependencies.mapTo(this) { moduleProvider.getModule(it.moduleName) }
testModule.allDependencies.mapTo(this) { moduleProvider.getModule(it.moduleName) as KtModule }
addIfNotNull(
libraryByRoots(
(configuration.jvmModularRoots + configuration.jvmClasspathRoots).map(File::toPath)
@@ -57,45 +56,72 @@ class TestKtSourceModule(
}
}
override val directRefinementDependencies: List<KtModule> by lazy(LazyThreadSafetyMode.PUBLICATION) {
val directRefinementDependencies: List<KtModule> by lazy(LazyThreadSafetyMode.PUBLICATION) {
testModule.dependsOnDependencies
.map { moduleProvider.getModule(it.moduleName) }
.map { moduleProvider.getModule(it.moduleName) as KtModule }
}
override val directFriendDependencies: List<KtModule> by lazy(LazyThreadSafetyMode.PUBLICATION) {
val directFriendDependencies: List<KtModule> by lazy(LazyThreadSafetyMode.PUBLICATION) {
buildList {
testModule.friendDependencies.mapTo(this) { moduleProvider.getModule(it.moduleName) }
testModule.friendDependencies.mapTo(this) { moduleProvider.getModule(it.moduleName) as KtModule }
addIfNotNull(
libraryByRoots(configuration[JVMConfigurationKeys.FRIEND_PATHS].orEmpty().map(Paths::get))
)
}
}
protected abstract val ktModule: KtModule
private fun libraryByRoots(roots: List<Path>): LibraryByRoots? {
if (roots.isEmpty()) return null
return LibraryByRoots(
roots,
this@TestKtSourceModule,
ktModule,
project,
)
}
override val contentScope: GlobalSearchScope =
TopDownAnalyzerFacadeForJVM.newModuleSearchScope(project, testFilesToKtFiles.values)
override val languageVersionSettings: LanguageVersionSettings
val languageVersionSettings: LanguageVersionSettings
get() = testModule.languageVersionSettings
override val platform: TargetPlatform
val platform: TargetPlatform
get() = testModule.targetPlatform
override val analyzerServices: PlatformDependentAnalyzerServices
val analyzerServices: PlatformDependentAnalyzerServices
get() = testModule.targetPlatform.getAnalyzerServices()
}
class TestKtSourceModule(
project: Project,
testModule: TestModule,
val testFilesToKtFiles: Map<TestFile, KtFile>,
testServices: TestServices
) : TestKtModule(project, testModule, testFilesToKtFiles.values.toSet(), testServices), KtSourceModule {
override val ktModule: KtModule get() = this
override val contentScope: GlobalSearchScope =
TopDownAnalyzerFacadeForJVM.newModuleSearchScope(project, testFilesToKtFiles.values)
}
class TestKtLibraryModule(
project: Project,
testModule: TestModule,
ktFiles: Collection<KtFile>,
testServices: TestServices
) : TestKtModule(project, testModule, ktFiles.toSet(), testServices), KtLibraryModule {
override val ktModule: KtModule get() = this
override val libraryName: String get() = testModule.name
override val librarySources: KtLibrarySourceModule? get() = null
override fun getBinaryRoots(): Collection<Path> = ktFiles.map { it.virtualFile.toNioPath() }
override val contentScope: GlobalSearchScope =
GlobalSearchScope.filesScope(project, ktFiles.map { it.virtualFile })
}
private class LibraryByRoots(
private val roots: List<Path>,
private val sourceModule: KtSourceModule,
private val module: KtModule,
override val project: Project,
) : KtLibraryModule {
override val libraryName: String get() = "Test Library"
@@ -103,8 +129,8 @@ private class LibraryByRoots(
override val directRefinementDependencies: List<KtModule> get() = emptyList()
override val directFriendDependencies: List<KtModule> get() = emptyList()
override val contentScope: GlobalSearchScope get() = ProjectScope.getLibrariesScope(project)
override val platform: TargetPlatform get() = sourceModule.platform
override val analyzerServices: PlatformDependentAnalyzerServices get() = sourceModule.analyzerServices
override val platform: TargetPlatform get() = module.platform
override val analyzerServices: PlatformDependentAnalyzerServices get() = module.analyzerServices
override fun getBinaryRoots(): Collection<Path> = roots
override val librarySources: KtLibrarySourceModule? get() = null
}