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
@@ -7,6 +7,7 @@ package org.jetbrains.kotlin.analysis.api.descriptors.test
import com.intellij.mock.MockProject
import com.intellij.openapi.Disposable
import org.jetbrains.kotlin.analysis.api.impl.barebone.test.TestKtSourceModule
import org.jetbrains.kotlin.analysis.api.impl.barebone.test.projectModuleProvider
import org.jetbrains.kotlin.analysis.providers.KotlinDeclarationProviderFactory
import org.jetbrains.kotlin.analysis.providers.KotlinModificationTrackerFactory
@@ -34,7 +35,7 @@ class KtFe10ModuleRegistrarPreAnalysisHandler(
ktFilesByModule.forEach { (testModule, ktFiles) ->
val project = testServices.compilerConfigurationProvider.getProject(testModule)
moduleInfoProvider.registerModuleInfo(project, testModule, ktFiles)
moduleInfoProvider.registerModuleInfo(testModule, TestKtSourceModule(project, testModule, ktFiles, testServices))
with(project as MockProject) {
registerService(KotlinModificationTrackerFactory::class.java, KotlinStaticModificationTrackerFactory::class.java)
@@ -12,6 +12,7 @@ import org.jetbrains.kotlin.analysis.api.InvalidWayOfUsingAnalysisSession
import org.jetbrains.kotlin.analysis.api.KtAnalysisSessionProvider
import org.jetbrains.kotlin.analysis.api.impl.barebone.test.FrontendApiTestConfiguratorService
import org.jetbrains.kotlin.analysis.api.impl.base.references.HLApiReferenceProviderService
import org.jetbrains.kotlin.analysis.low.level.api.fir.compiler.based.registerTestServices
import org.jetbrains.kotlin.analysis.low.level.api.fir.test.base.FirLowLevelFrontendApiTestConfiguratorService
import org.jetbrains.kotlin.idea.references.KotlinFirReferenceContributor
import org.jetbrains.kotlin.idea.references.KotlinReferenceProviderContributor
@@ -32,10 +33,8 @@ object FirFrontendApiTestConfiguratorService : FrontendApiTestConfiguratorServic
return FirLowLevelFrontendApiTestConfiguratorService.getOriginalFile(file)
}
@OptIn(InvalidWayOfUsingAnalysisSession::class)
override fun registerProjectServices(project: MockProject) {
FirLowLevelFrontendApiTestConfiguratorService.registerProjectServices(project)
project.registerService(KtAnalysisSessionProvider::class.java, KtFirAnalysisSessionProvider::class.java)
}
override fun registerApplicationServices(application: MockApplication) {
@@ -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
}
@@ -16,7 +16,7 @@ import com.intellij.util.cls.ClsFormatException
import com.intellij.util.containers.ContainerUtil
import java.io.IOException
internal class ClsJavaStubByVirtualFileCache {
class ClsJavaStubByVirtualFileCache {
private class CachedJavaStub(val modificationStamp: Long, val javaFileStub: PsiJavaFileStubImpl)
private val cache = ContainerUtil.createConcurrentWeakKeySoftValueMap<VirtualFile, CachedJavaStub>()
@@ -7,11 +7,13 @@ package org.jetbrains.kotlin.analysis.low.level.api.fir.compiler.based
import org.jetbrains.kotlin.analysis.api.impl.barebone.test.AbstractCompilerBasedTest
import org.jetbrains.kotlin.analysis.api.impl.barebone.test.TestKtModuleProvider
import org.jetbrains.kotlin.analysis.api.impl.barebone.test.TestKtSourceModule
import org.jetbrains.kotlin.analysis.api.impl.barebone.test.projectModuleProvider
import org.jetbrains.kotlin.analysis.low.level.api.fir.api.DiagnosticCheckerFilter
import org.jetbrains.kotlin.analysis.low.level.api.fir.api.getOrBuildFirFile
import org.jetbrains.kotlin.analysis.low.level.api.fir.createResolveStateForNoCaching
import org.jetbrains.kotlin.analysis.low.level.api.fir.transformers.FirLazyTransformerForIDE
import org.jetbrains.kotlin.analysis.project.structure.KtModule
import org.jetbrains.kotlin.platform.jvm.JvmPlatforms
import org.jetbrains.kotlin.test.bind
import org.jetbrains.kotlin.test.builders.TestConfigurationBuilder
@@ -57,7 +59,7 @@ abstract class AbstractCompilerBasedTestForFir : AbstractCompilerBasedTest() {
override fun analyze(module: TestModule): FirOutputArtifact {
val moduleInfoProvider = testServices.projectModuleProvider
val moduleInfo = moduleInfoProvider.getModule(module.name)
val moduleInfo = moduleInfoProvider.getModule(module.name) as TestKtSourceModule
val project = testServices.compilerConfigurationProvider.getProject(module)
val resolveState = createResolveStateForNoCaching(moduleInfo, project)
@@ -7,6 +7,7 @@ package org.jetbrains.kotlin.analysis.low.level.api.fir.compiler.based
import com.intellij.mock.MockProject
import com.intellij.openapi.Disposable
import org.jetbrains.kotlin.analysis.api.impl.barebone.test.TestKtSourceModule
import org.jetbrains.kotlin.analysis.api.impl.barebone.test.projectModuleProvider
import org.jetbrains.kotlin.analysis.low.level.api.fir.api.getOrBuildFirFile
import org.jetbrains.kotlin.analysis.low.level.api.fir.api.getResolveState
@@ -24,6 +25,7 @@ class ModuleRegistrarPreAnalysisHandler(
) : PreAnalysisHandler(testServices) {
private val moduleInfoProvider = testServices.projectModuleProvider
override fun preprocessModuleStructure(moduleStructure: TestModuleStructure) {
// todo rework after all modules will have the same Project instance
val ktFilesByModule = moduleStructure.modules.associateWith { testModule ->
@@ -35,7 +37,7 @@ class ModuleRegistrarPreAnalysisHandler(
ktFilesByModule.forEach { (testModule, ktFiles) ->
val project = testServices.compilerConfigurationProvider.getProject(testModule)
moduleInfoProvider.registerModuleInfo(project, testModule, ktFiles)
moduleInfoProvider.registerModuleInfo(testModule, TestKtSourceModule(project, testModule, ktFiles, testServices))
(project as MockProject).registerTestServices(testModule, allKtFiles, testServices)
// Manually process all inheritors of sealed classes so that SealedClassInheritorsProviderTestImpl can work correctly for tests.
@@ -57,4 +59,4 @@ class ModuleRegistrarPreAnalysisHandler(
}
}
}
}
}
@@ -85,7 +85,7 @@ private class KotlinProjectStructureProviderTestImpl(testServices: TestServices)
private val moduleInfoProvider = testServices.projectModuleProvider
override fun getKtModuleForKtElement(element: PsiElement): KtModule {
val containingFile = element.containingFile as KtFile
return moduleInfoProvider.getModuleInfoByKtFile(containingFile)
return moduleInfoProvider.getModuleInfoByKtFile(containingFile) as KtModule
}
}
+13 -1
View File
@@ -14,9 +14,21 @@ dependencies {
implementation(project(":analysis:project-structure"))
implementation(project(":analysis:decompiled:light-classes-for-decompiled"))
implementation(intellijCore())
testImplementation(project(":analysis:decompiled:decompiler-to-file-stubs"))
testImplementation(projectTests(":analysis:analysis-api-impl-base"))
testImplementation(projectTests(":analysis:analysis-api-fir"))
}
sourceSets {
"main" { projectDefault() }
"test" { none() }
"test" { projectDefault() }
}
projectTest(jUnitMode = JUnitMode.JUnit5) {
dependsOn(":dist")
workingDir = rootDir
useJUnitPlatform()
}
testsJar()
@@ -0,0 +1,13 @@
package org.jetbrains.annotations;
import java.lang.annotation.*;
@Documented
@Retention(RetentionPolicy.CLASS)
@Target({ElementType.METHOD, ElementType.FIELD, ElementType.PARAMETER, ElementType.LOCAL_VARIABLE})
public @interface NotNull {
String value() default "";
Class<? extends Exception> exception() default Exception.class;
}
@@ -0,0 +1,10 @@
package org.jetbrains.annotations;
import java.lang.annotation.*;
@Documented
@Retention(RetentionPolicy.CLASS)
@Target({ElementType.METHOD, ElementType.FIELD, ElementType.PARAMETER, ElementType.LOCAL_VARIABLE})
public @interface Nullable {
@NonNls String value() default "";
}
@@ -0,0 +1,42 @@
/*
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
* 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.light.classes.symbol.base
import com.intellij.openapi.project.Project
import com.intellij.psi.search.GlobalSearchScope
import org.jetbrains.kotlin.analysis.api.impl.barebone.test.FrontendApiTestConfiguratorService
import org.jetbrains.kotlin.asJava.KotlinAsJavaSupport
import org.jetbrains.kotlin.asJava.classes.KtLightClass
import org.jetbrains.kotlin.asJava.renderClass
import org.jetbrains.kotlin.light.classes.symbol.base.service.withExtendedTypeRenderer
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.test.model.TestModule
import java.nio.file.Path
abstract class AbstractSymbolLightClassesFacadeTest(
configurator: FrontendApiTestConfiguratorService,
override val currentExtension: String,
override val stopIfCompilationErrorDirectivePresent: Boolean,
) : AbstractSymbolLightClassesTestBase(configurator) {
override fun getRenderResult(ktFile: KtFile, testDataFile: Path, module: TestModule, project: Project): String {
val lightClasses = getFacades(project)
return withExtendedTypeRenderer((testDataFile)) {
lightClasses.joinToString("\n\n") { it.renderClass() }
}
}
private fun getFacades(
project: Project
): List<KtLightClass> {
val kotlinAsJavaSupport = KotlinAsJavaSupport.getInstance(project)
val scope = GlobalSearchScope.allScope(project)
val facades = kotlinAsJavaSupport.getFacadeNames(FqName.ROOT, scope).sorted()
return facades
.flatMap { facadeName -> kotlinAsJavaSupport.getFacadeClasses(FqName(facadeName), scope) }
.filterIsInstance<KtLightClass>()
}
}
@@ -0,0 +1,41 @@
/*
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
* 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.light.classes.symbol.base
import com.intellij.openapi.project.Project
import com.intellij.psi.SyntaxTraverser
import org.jetbrains.kotlin.analysis.api.impl.barebone.test.FrontendApiTestConfiguratorService
import org.jetbrains.kotlin.asJava.KotlinAsJavaSupport
import org.jetbrains.kotlin.asJava.classes.KtLightClass
import org.jetbrains.kotlin.asJava.renderClass
import org.jetbrains.kotlin.light.classes.symbol.base.service.withExtendedTypeRenderer
import org.jetbrains.kotlin.psi.KtClassOrObject
import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.test.model.TestModule
import java.nio.file.Path
abstract class AbstractSymbolLightClassesLoadingTest(
configurator: FrontendApiTestConfiguratorService,
override val currentExtension: String,
override val stopIfCompilationErrorDirectivePresent: Boolean,
) : AbstractSymbolLightClassesTestBase(configurator) {
override fun getRenderResult(ktFile: KtFile, testDataFile: Path, module: TestModule, project: Project): String {
val lightClasses = getLightClassesFromFile(ktFile, project)
return withExtendedTypeRenderer(testDataFile) {
lightClasses.joinToString("\n\n") { it.renderClass() }
}
}
private fun getLightClassesFromFile(
ktFile: KtFile,
project: Project
): List<KtLightClass> {
val ktClasses = SyntaxTraverser.psiTraverser(ktFile).filter(KtClassOrObject::class.java).toList()
val kotlinAsJavaSupport = KotlinAsJavaSupport.getInstance(project)
return ktClasses.mapNotNull(kotlinAsJavaSupport::getLightClass)
}
}
@@ -0,0 +1,36 @@
/*
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
* 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.light.classes.symbol.base
import com.intellij.openapi.project.Project
import com.intellij.psi.PsiClass
import com.intellij.psi.search.GlobalSearchScope
import org.jetbrains.kotlin.analysis.api.impl.barebone.test.FrontendApiTestConfiguratorService
import org.jetbrains.kotlin.asJava.LightClassTestCommon
import org.jetbrains.kotlin.asJava.finder.JavaElementFinder
import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.test.model.TestModule
import java.nio.file.Path
abstract class AbstractSymbolLightClassesTest(
configurator: FrontendApiTestConfiguratorService,
override val currentExtension: String,
override val stopIfCompilationErrorDirectivePresent: Boolean,
) : AbstractSymbolLightClassesTestBase(configurator) {
override fun getRenderResult(ktFile: KtFile, testDataFile: Path, module: TestModule, project: Project): String {
return LightClassTestCommon.getActualLightClassText(
testDataFile.toFile(),
{ fqName -> findLightClass(fqName, project) },
LightClassTestCommon::removeEmptyDefaultImpls
)
}
private fun findLightClass(fqname: String, project: Project): PsiClass? {
return JavaElementFinder
.getInstance(project)
.findClass(fqname, GlobalSearchScope.allScope(project))
}
}
@@ -0,0 +1,147 @@
/*
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
* 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.light.classes.symbol.base
import com.intellij.openapi.project.Project
import com.intellij.psi.PsiClass
import com.intellij.psi.search.GlobalSearchScope
import org.jetbrains.kotlin.analysis.api.impl.barebone.test.FrontendApiTestConfiguratorService
import org.jetbrains.kotlin.analysis.api.impl.base.test.test.framework.AbstractHLApiSingleModuleTest
import org.jetbrains.kotlin.asJava.finder.JavaElementFinder
import org.jetbrains.kotlin.light.classes.symbol.base.service.NullabilityAnnotationSourceProvider
import org.jetbrains.kotlin.light.classes.symbol.decompiled.service.CompilerExecutor
import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.test.builders.TestConfigurationBuilder
import org.jetbrains.kotlin.test.directives.model.DirectiveApplicability
import org.jetbrains.kotlin.test.directives.model.SimpleDirectivesContainer
import org.jetbrains.kotlin.test.model.TestModule
import org.jetbrains.kotlin.test.services.TestModuleStructure
import org.jetbrains.kotlin.test.services.TestServices
import org.jetbrains.kotlin.test.services.assertions
import org.jetbrains.kotlin.test.utils.FirIdenticalCheckerHelper
import java.io.File
import java.nio.file.Path
import kotlin.io.path.exists
import kotlin.io.path.nameWithoutExtension
abstract class AbstractSymbolLightClassesTestBase(
configurator: FrontendApiTestConfiguratorService
) : AbstractHLApiSingleModuleTest(configurator) {
override val enableTestInDependedMode: Boolean get() = false
override fun configureTest(builder: TestConfigurationBuilder) {
super.configureTest(builder)
with(builder) {
useDirectives(Directives, CompilerExecutor.Directives)
useAdditionalSourceProviders(::NullabilityAnnotationSourceProvider)
}
}
override fun handleInitializationError(exception: Throwable, moduleStructure: TestModuleStructure): InitializationErrorAction {
return if (Directives.IGNORE_FIR in moduleStructure.allDirectives) InitializationErrorAction.IGNORE
else InitializationErrorAction.THROW
}
override fun doTestByFileStructure(ktFiles: List<KtFile>, module: TestModule, testServices: TestServices) {
if (stopIfCompilationErrorDirectivePresent && CompilerExecutor.Directives.COMPILATION_ERRORS in module.directives) {
return
}
val testDataFile = module.files.first { it.name.endsWith(".kt") }.originalFile.toPath()
val project = ktFiles.first().project
ignoreExceptionIfIgnoreFirPresent(module) {
val actual = getRenderResult(ktFiles.first(), testDataFile, module, project)
compareResults(testServices, actual)
removeIgnoreFir(module)
removeDuplicatedFirJava(testServices)
}
}
protected abstract fun getRenderResult(
ktFile: KtFile,
testDataFile: Path,
module: TestModule,
project: Project
): String
private inline fun ignoreExceptionIfIgnoreFirPresent(module: TestModule, action: () -> Unit) {
try {
action()
} catch (e: Throwable) {
if (Directives.IGNORE_FIR in module.directives) {
return
}
throw e
}
}
private fun compareResults(
testServices: TestServices,
actual: String,
) {
if (currentResultPath().exists()) {
testServices.assertions.assertEqualsToFile(currentResultPath(), actual)
} else {
testServices.assertions.assertEqualsToFile(javaPath(), actual)
}
}
private fun removeIgnoreFir(module: TestModule) {
if (Directives.IGNORE_FIR in module.directives) {
error("Test is passing. Please, remove `// ${Directives.IGNORE_FIR.name}` directive")
}
}
private fun findLightClass(fqname: String, project: Project): PsiClass? {
return JavaElementFinder
.getInstance(project)
.findClass(fqname, GlobalSearchScope.allScope(project))
}
private fun removeDuplicatedFirJava(testServices: TestServices) {
val java = javaPath()
val firJava = currentResultPath()
if (!firJava.exists()) return
val identicalCheckerHelper = IdenticalCheckerHelper(testServices)
if (identicalCheckerHelper.contentsAreEquals(java.toFile(), firJava.toFile(), trimLines = true)) {
identicalCheckerHelper.deleteFirFile(java.toFile())
}
}
private inner class IdenticalCheckerHelper(testServices: TestServices) : FirIdenticalCheckerHelper(testServices) {
override fun getClassicFileToCompare(testDataFile: File): File {
return if (testDataFile.name.endsWith(EXTENSIONS.FIR_JAVA))
testDataFile.resolveSibling(testDataFile.name.removeSuffix(currentExtension) + EXTENSIONS.JAVA)
else testDataFile
}
override fun getFirFileToCompare(testDataFile: File): File {
return if (testDataFile.name.endsWith(EXTENSIONS.FIR_JAVA))
testDataFile
else testDataFile.resolveSibling(testDataFile.name.removeSuffix(EXTENSIONS.JAVA) + currentExtension)
}
}
private fun javaPath() = testDataPath.resolveSibling(testDataPath.nameWithoutExtension + EXTENSIONS.JAVA)
private fun currentResultPath() = testDataPath.resolveSibling(testDataPath.nameWithoutExtension + currentExtension)
protected abstract val currentExtension: String
protected abstract val stopIfCompilationErrorDirectivePresent: Boolean
object EXTENSIONS {
const val JAVA = ".java"
const val FIR_JAVA = ".fir.java"
const val LIB_JAVA = ".lib.java"
}
private object Directives : SimpleDirectivesContainer() {
val IGNORE_FIR by directive(
description = "Ignore the test for Symbol FIR-based implementation of LC",
applicability = DirectiveApplicability.Global
)
}
}
@@ -0,0 +1,24 @@
/*
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
* 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.light.classes.symbol.base.service
import org.jetbrains.kotlin.test.directives.model.RegisteredDirectives
import org.jetbrains.kotlin.test.model.TestFile
import org.jetbrains.kotlin.test.model.TestModule
import org.jetbrains.kotlin.test.services.AdditionalSourceProvider
import org.jetbrains.kotlin.test.services.TestServices
import java.io.File
class NullabilityAnnotationSourceProvider(testServices: TestServices) : AdditionalSourceProvider(testServices) {
override fun produceAdditionalFiles(globalDirectives: RegisteredDirectives, module: TestModule): List<TestFile> {
return listOf(
"analysis/symbol-light-classes/testdata/additionalFiles/NotNull.java",
"analysis/symbol-light-classes/testdata/additionalFiles/Nullable.java",
).map { path ->
File(path).toTestFile(relativePath = "org/jetbrains/annotations")
}
}
}
@@ -0,0 +1,19 @@
/*
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
* 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.light.classes.symbol.base.service
import org.jetbrains.kotlin.asJava.PsiClassRenderer
import java.nio.file.Path
internal inline fun <R> withExtendedTypeRenderer(testDataFile: Path, action: () -> R): R {
val extendedTypeRendererOld = PsiClassRenderer.extendedTypeRenderer
return try {
PsiClassRenderer.extendedTypeRenderer = testDataFile.toString().endsWith("typeAnnotations.kt")
action()
} finally {
PsiClassRenderer.extendedTypeRenderer = extendedTypeRendererOld
}
}
@@ -0,0 +1,18 @@
/*
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
* 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.light.classes.symbol.decompiled
import org.jetbrains.kotlin.light.classes.symbol.base.AbstractSymbolLightClassesFacadeTest
import org.jetbrains.kotlin.light.classes.symbol.decompiled.service.SymbolLightClassesForLibraryFrontendApiTestConfiguratorService
import org.junit.jupiter.api.parallel.Execution
import org.junit.jupiter.api.parallel.ExecutionMode
abstract class AbstractSymbolLightClassesFacadeForLibraryTest :
AbstractSymbolLightClassesFacadeTest(
SymbolLightClassesForLibraryFrontendApiTestConfiguratorService,
EXTENSIONS.LIB_JAVA,
stopIfCompilationErrorDirectivePresent = true
)
@@ -0,0 +1,18 @@
/*
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
* 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.light.classes.symbol.decompiled
import org.jetbrains.kotlin.light.classes.symbol.base.AbstractSymbolLightClassesTest
import org.jetbrains.kotlin.light.classes.symbol.decompiled.service.SymbolLightClassesForLibraryFrontendApiTestConfiguratorService
import org.junit.jupiter.api.parallel.Execution
import org.junit.jupiter.api.parallel.ExecutionMode
abstract class AbstractSymbolLightClassesForLibraryTest :
AbstractSymbolLightClassesTest(
SymbolLightClassesForLibraryFrontendApiTestConfiguratorService,
EXTENSIONS.LIB_JAVA,
stopIfCompilationErrorDirectivePresent = true
)
@@ -0,0 +1,18 @@
/*
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
* 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.light.classes.symbol.decompiled
import org.jetbrains.kotlin.light.classes.symbol.base.AbstractSymbolLightClassesLoadingTest
import org.jetbrains.kotlin.light.classes.symbol.decompiled.service.SymbolLightClassesForLibraryFrontendApiTestConfiguratorService
import org.junit.jupiter.api.parallel.Execution
import org.junit.jupiter.api.parallel.ExecutionMode
abstract class AbstractSymbolLightClassesLoadingForLibraryTest :
AbstractSymbolLightClassesLoadingTest(
SymbolLightClassesForLibraryFrontendApiTestConfiguratorService,
EXTENSIONS.LIB_JAVA,
stopIfCompilationErrorDirectivePresent = true
)
@@ -0,0 +1,59 @@
/*
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
* 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.light.classes.symbol.decompiled.service
import org.jetbrains.kotlin.test.MockLibraryUtil
import org.jetbrains.kotlin.test.directives.JvmEnvironmentConfigurationDirectives
import org.jetbrains.kotlin.test.directives.LanguageSettingsDirectives
import org.jetbrains.kotlin.test.directives.model.SimpleDirectivesContainer
import org.jetbrains.kotlin.test.model.TestModule
import java.nio.file.Path
import kotlin.io.path.absolutePathString
import kotlin.io.path.div
import kotlin.io.path.exists
import kotlin.io.path.notExists
object CompilerExecutor {
fun compileLibrary(sourcesPath: Path, options: List<String>, compilationErrorExpected: Boolean): Path? {
val library = sourcesPath / "library.jar"
val sourceFiles = sourcesPath.toFile().walkBottomUp()
val commands = buildList {
sourceFiles.mapTo(this) { it.absolutePath }
addAll(options)
add("-d")
add(library.absolutePathString())
}
try {
MockLibraryUtil.runJvmCompiler(commands)
} catch (e: Throwable) {
if (!compilationErrorExpected) {
throw IllegalStateException("Unexpected compilation error while compiling library", e)
}
}
if (library.exists() && compilationErrorExpected) {
error("Compilation error expected but, code was compiled successfully")
}
return library.takeIf(Path::exists)
}
fun parseCompilerOptionsFromTestdata(module: TestModule): List<String> = buildList {
module.directives[LanguageSettingsDirectives.API_VERSION].firstOrNull()?.let { apiVersion ->
addAll(listOf("-api-version", apiVersion.versionString))
}
module.directives[JvmEnvironmentConfigurationDirectives.JVM_TARGET].firstOrNull()?.let { jvmTarget ->
addAll(listOf("-jvm-target", jvmTarget.description))
}
addAll(module.directives[Directives.COMPILER_ARGUMENTS])
}
object Directives : SimpleDirectivesContainer() {
val COMPILER_ARGUMENTS by stringDirective("List of additional compiler arguments")
val COMPILATION_ERRORS by directive("Is compilation errors expected in the file")
}
}
@@ -0,0 +1,79 @@
/*
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
* 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.light.classes.symbol.decompiled.service
import com.intellij.mock.MockProject
import com.intellij.openapi.project.Project
import com.intellij.openapi.vfs.VfsUtilCore
import com.intellij.openapi.vfs.VirtualFile
import com.intellij.openapi.vfs.impl.jar.CoreJarFileSystem
import com.intellij.psi.PsiManager
import org.jetbrains.kotlin.analysis.api.impl.barebone.test.TestKtLibraryModule
import org.jetbrains.kotlin.analysis.api.impl.barebone.test.projectModuleProvider
import org.jetbrains.kotlin.analysis.decompiler.psi.file.KtClsFile
import org.jetbrains.kotlin.analysis.low.level.api.fir.compiler.based.registerTestServices
import org.jetbrains.kotlin.test.model.TestModule
import org.jetbrains.kotlin.test.services.*
import org.jetbrains.kotlin.test.util.KtTestUtil
import java.nio.file.Path
import kotlin.io.path.absolutePathString
import kotlin.io.path.createFile
import kotlin.io.path.div
import kotlin.io.path.writeText
class LibraryModuleRegistrarPreAnalysisHandler(
testServices: TestServices
) : PreAnalysisHandler(testServices) {
private val moduleInfoProvider = testServices.projectModuleProvider
override fun preprocessModuleStructure(moduleStructure: TestModuleStructure) {
val testModule = moduleStructure.modules.single()
val project = testServices.compilerConfigurationProvider.getProject(testModule)
val decompiledKtFiles = getDecompiledVirtualFilesFromLibrary(testModule, project)
moduleInfoProvider.registerModuleInfo(testModule, TestKtLibraryModule(project, testModule, decompiledKtFiles, testServices))
(project as MockProject).registerTestServices(testModule, decompiledKtFiles, testServices)
}
private fun getDecompiledVirtualFilesFromLibrary(module: TestModule, project: Project): List<KtClsFile> {
val tmpDir = KtTestUtil.tmpDir("testSourcesToCompile").toPath()
for (testFile in module.files) {
val text = testServices.sourceFileProvider.getContentOfSourceFile(testFile)
val tmpSourceFile = (tmpDir / testFile.name).createFile()
tmpSourceFile.writeText(text)
}
val library = CompilerExecutor.compileLibrary(
tmpDir,
CompilerExecutor.parseCompilerOptionsFromTestdata(module),
compilationErrorExpected = CompilerExecutor.Directives.COMPILATION_ERRORS in module.directives
) ?: return emptyList()
val virtualFiles = getAllVirtualFilesFromLibrary(library)
return virtualFiles.mapNotNull { virtualFile ->
PsiManager.getInstance(project).findFile(virtualFile) as? KtClsFile
}
}
private fun getAllVirtualFilesFromLibrary(library: Path): Collection<VirtualFile> {
val jarFileSystem = CoreJarFileSystem()
val root = jarFileSystem.refreshAndFindFileByPath(library.absolutePathString() + "!/")!!
val files = mutableSetOf<VirtualFile>()
VfsUtilCore.iterateChildrenRecursively(
root,
/*filter=*/{ true },
/*iterator=*/{ virtualFile ->
if (!virtualFile.isDirectory) {
files.add(virtualFile)
}
true
}
)
return files
}
}
@@ -0,0 +1,68 @@
/*
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
* 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.light.classes.symbol.decompiled.service
import com.intellij.ide.highlighter.JavaClassFileType
import com.intellij.mock.MockApplication
import com.intellij.mock.MockProject
import com.intellij.openapi.Disposable
import com.intellij.openapi.extensions.LoadingOrder
import com.intellij.openapi.vfs.VirtualFile
import com.intellij.psi.ClassFileViewProviderFactory
import com.intellij.psi.FileTypeFileViewProviders
import com.intellij.psi.compiled.ClassFileDecompilers
import org.jetbrains.kotlin.analysis.api.fir.FirFrontendApiTestConfiguratorService
import org.jetbrains.kotlin.analysis.api.impl.barebone.test.FrontendApiTestConfiguratorService
import org.jetbrains.kotlin.analysis.decompiled.light.classes.ClsJavaStubByVirtualFileCache
import org.jetbrains.kotlin.analysis.decompiler.psi.KotlinBuiltInDecompiler
import org.jetbrains.kotlin.analysis.decompiler.psi.KotlinClassFileDecompiler
import org.jetbrains.kotlin.analysis.decompiler.stub.file.CachedAttributeData
import org.jetbrains.kotlin.analysis.decompiler.stub.file.ClsKotlinBinaryClassCache
import org.jetbrains.kotlin.analysis.decompiler.stub.file.FileAttributeService
import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.test.builders.TestConfigurationBuilder
import java.io.DataInput
import java.io.DataOutput
object SymbolLightClassesForLibraryFrontendApiTestConfiguratorService : FrontendApiTestConfiguratorService {
override fun TestConfigurationBuilder.configureTest(disposable: Disposable) {
usePreAnalysisHandlers(::LibraryModuleRegistrarPreAnalysisHandler)
}
override fun registerProjectServices(project: MockProject) {
project.registerService(ClsJavaStubByVirtualFileCache::class.java)
}
override fun registerApplicationServices(application: MockApplication) {
FirFrontendApiTestConfiguratorService.registerApplicationServices(application)
if (application.getServiceIfCreated(ClsKotlinBinaryClassCache::class.java) != null) return
application.registerService(ClsKotlinBinaryClassCache::class.java)
application.registerService(FileAttributeService::class.java, DummyFileAttributeService)
FileTypeFileViewProviders.INSTANCE.addExplicitExtension(
JavaClassFileType.INSTANCE,
ClassFileViewProviderFactory()
)
@Suppress("DEPRECATION")
ClassFileDecompilers.getInstance().EP_NAME.point.registerExtension(KotlinClassFileDecompiler(), LoadingOrder.FIRST)
@Suppress("DEPRECATION")
ClassFileDecompilers.getInstance().EP_NAME.point.registerExtension(KotlinBuiltInDecompiler(), LoadingOrder.FIRST)
}
override fun doOutOfBlockModification(file: KtFile) {
FirFrontendApiTestConfiguratorService.doOutOfBlockModification(file)
}
}
private object DummyFileAttributeService : FileAttributeService {
override fun <T> write(file: VirtualFile, id: String, value: T, writeValueFun: (DataOutput, T) -> Unit): CachedAttributeData<T> {
return CachedAttributeData(value, 0)
}
override fun <T> read(file: VirtualFile, id: String, readValueFun: (DataInput) -> T): CachedAttributeData<T>? {
return null
}
}
@@ -0,0 +1,16 @@
/*
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
* 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.light.classes.symbol.source
import org.jetbrains.kotlin.analysis.api.fir.FirFrontendApiTestConfiguratorService
import org.jetbrains.kotlin.light.classes.symbol.base.AbstractSymbolLightClassesFacadeTest
abstract class AbstractSymbolLightClassesFacadeForSourceTest :
AbstractSymbolLightClassesFacadeTest(
FirFrontendApiTestConfiguratorService,
EXTENSIONS.FIR_JAVA,
stopIfCompilationErrorDirectivePresent = false
)
@@ -0,0 +1,16 @@
/*
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
* 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.light.classes.symbol.source
import org.jetbrains.kotlin.analysis.api.fir.FirFrontendApiTestConfiguratorService
import org.jetbrains.kotlin.light.classes.symbol.base.AbstractSymbolLightClassesTest
abstract class AbstractSymbolLightClassesForSourceTest :
AbstractSymbolLightClassesTest(
FirFrontendApiTestConfiguratorService,
EXTENSIONS.FIR_JAVA,
stopIfCompilationErrorDirectivePresent = false
)
@@ -0,0 +1,16 @@
/*
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
* 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.light.classes.symbol.source
import org.jetbrains.kotlin.analysis.api.fir.FirFrontendApiTestConfiguratorService
import org.jetbrains.kotlin.light.classes.symbol.base.AbstractSymbolLightClassesLoadingTest
abstract class AbstractSymbolLightClassesLoadingForSourceTest :
AbstractSymbolLightClassesLoadingTest(
FirFrontendApiTestConfiguratorService,
EXTENSIONS.FIR_JAVA,
stopIfCompilationErrorDirectivePresent = false
)
+2 -1
View File
@@ -817,7 +817,8 @@ tasks {
":analysis:analysis-api:test",
":analysis:analysis-api-fir:test",
":analysis:analysis-api-fe10:test",
":analysis:low-level-api-fir:test"
":analysis:low-level-api-fir:test",
":analysis:symbol-light-classes:test"
)
}
@@ -11,6 +11,7 @@ import org.jetbrains.kotlin.test.model.ServicesAndDirectivesContainer
import org.jetbrains.kotlin.test.model.TestFile
import org.jetbrains.kotlin.test.model.TestModule
import java.io.File
import java.nio.file.Paths
abstract class AdditionalSourceProvider(val testServices: TestServices) : ServicesAndDirectivesContainer {
/**
@@ -22,9 +23,9 @@ abstract class AdditionalSourceProvider(val testServices: TestServices) : Servic
return globalDirectives.contains(directive) || module.directives.contains(directive)
}
protected fun File.toTestFile(): TestFile {
protected fun File.toTestFile(relativePath: String? = null): TestFile {
return TestFile(
this.name,
relativePath?.let(Paths::get)?.resolve(name)?.toString() ?: name,
this.readText(),
originalFile = this,
startLineNumberInOriginalFile = 0,
@@ -165,7 +165,7 @@ object MockLibraryUtil {
return jarFile
}
private fun runJvmCompiler(args: List<String>) {
fun runJvmCompiler(args: List<String>) {
runCompiler(compiler2JVMClass, args)
}
@@ -18,6 +18,7 @@ dependencies {
testApi(projectTests(":analysis:analysis-api-fir"))
testApi(projectTests(":analysis:analysis-api-fe10"))
testApi(projectTests(":analysis:decompiled:decompiler-to-file-stubs"))
testApi(projectTests(":analysis:symbol-light-classes"))
testApi(intellijCore())
testApiJUnit5()
}
@@ -19,4 +19,5 @@ private fun TestGroupSuite.generateTests() {
generateAnalysisApiTests()
generateFirLowLevelApiTests()
generateDecompiledTests()
generateSymbolLightClassesTests()
}
@@ -0,0 +1,59 @@
/*
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
* 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.generators.tests.analysis.api
import org.jetbrains.kotlin.generators.TestGroupSuite
import org.jetbrains.kotlin.generators.util.TestGeneratorUtil
import org.jetbrains.kotlin.light.classes.symbol.decompiled.AbstractSymbolLightClassesFacadeForLibraryTest
import org.jetbrains.kotlin.light.classes.symbol.decompiled.AbstractSymbolLightClassesForLibraryTest
import org.jetbrains.kotlin.light.classes.symbol.decompiled.AbstractSymbolLightClassesLoadingForLibraryTest
import org.jetbrains.kotlin.light.classes.symbol.source.AbstractSymbolLightClassesFacadeForSourceTest
import org.jetbrains.kotlin.light.classes.symbol.source.AbstractSymbolLightClassesForSourceTest
import org.jetbrains.kotlin.light.classes.symbol.source.AbstractSymbolLightClassesLoadingForSourceTest
internal fun TestGroupSuite.generateSymbolLightClassesTests() {
testGroup(
"analysis/symbol-light-classes/tests",
"compiler/testData",
) {
run {
testClass<AbstractSymbolLightClassesForSourceTest> {
model(
"asJava/lightClasses",
pattern = TestGeneratorUtil.KT_WITHOUT_DOTS_IN_NAME
)
}
testClass<AbstractSymbolLightClassesForLibraryTest> {
model(
"asJava/lightClasses",
excludeDirs = listOf("compilationErrors"),
pattern = TestGeneratorUtil.KT_WITHOUT_DOTS_IN_NAME
)
}
}
run {
testClass<AbstractSymbolLightClassesLoadingForSourceTest> {
model("asJava/ultraLightClasses", pattern = TestGeneratorUtil.KT)
}
testClass<AbstractSymbolLightClassesLoadingForLibraryTest> {
model("asJava/ultraLightClasses", pattern = TestGeneratorUtil.KT)
}
}
run {
testClass<AbstractSymbolLightClassesFacadeForSourceTest> {
model("asJava/ultraLightFacades", pattern = TestGeneratorUtil.KT)
}
testClass<AbstractSymbolLightClassesFacadeForLibraryTest> {
model("asJava/ultraLightFacades", pattern = TestGeneratorUtil.KT)
}
}
}
}
@@ -11,6 +11,7 @@ import java.lang.StringBuilder
object TestGeneratorUtil {
@Language("RegExp") const val KT_OR_KTS = """^(.+)\.(kt|kts)$"""
@Language("RegExp") const val KT = """^(.+)\.(kt)$"""
@Language("RegExp") const val KT_OR_KTS_WITHOUT_DOTS_IN_NAME = """^([^.]+)\.(kt|kts)$"""
@Language("RegExp") const val KT_WITHOUT_DOTS_IN_NAME = """^([^.]+)\.kt$"""