Analysis LC: introduce Symbol LC tests
This commit is contained in:
+2
-1
@@ -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)
|
||||
|
||||
+1
-2
@@ -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) {
|
||||
|
||||
+31
-14
@@ -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
-7
@@ -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)
|
||||
}
|
||||
|
||||
|
||||
+48
-22
@@ -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
|
||||
}
|
||||
|
||||
+1
-1
@@ -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>()
|
||||
|
||||
+3
-1
@@ -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)
|
||||
|
||||
+4
-2
@@ -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(
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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 "";
|
||||
}
|
||||
+42
@@ -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>()
|
||||
}
|
||||
}
|
||||
+41
@@ -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)
|
||||
}
|
||||
}
|
||||
+36
@@ -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))
|
||||
}
|
||||
}
|
||||
+147
@@ -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
|
||||
)
|
||||
}
|
||||
}
|
||||
+24
@@ -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")
|
||||
}
|
||||
}
|
||||
}
|
||||
+19
@@ -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
|
||||
}
|
||||
}
|
||||
+18
@@ -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
|
||||
)
|
||||
+18
@@ -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
|
||||
)
|
||||
+18
@@ -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
|
||||
)
|
||||
+59
@@ -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")
|
||||
}
|
||||
}
|
||||
+79
@@ -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
|
||||
}
|
||||
}
|
||||
+68
@@ -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
|
||||
}
|
||||
}
|
||||
+16
@@ -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
|
||||
)
|
||||
+16
@@ -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
|
||||
)
|
||||
+16
@@ -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
@@ -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"
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
+3
-2
@@ -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()
|
||||
}
|
||||
|
||||
+1
@@ -19,4 +19,5 @@ private fun TestGroupSuite.generateTests() {
|
||||
generateAnalysisApiTests()
|
||||
generateFirLowLevelApiTests()
|
||||
generateDecompiledTests()
|
||||
generateSymbolLightClassesTests()
|
||||
}
|
||||
|
||||
+59
@@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+1
@@ -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$"""
|
||||
|
||||
Reference in New Issue
Block a user