Analysis LC: introduce Symbol LC tests
This commit is contained in:
@@ -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
|
||||
)
|
||||
Reference in New Issue
Block a user