diff --git a/analysis/decompiled/decompiler-to-file-stubs/tests/org/jetbrains/kotlin/analysis/decompiler/stub/files/AbstractClsStubBuilderTest.kt b/analysis/decompiled/decompiler-to-file-stubs/tests/org/jetbrains/kotlin/analysis/decompiler/stub/files/AbstractClsStubBuilderTest.kt index 896355eb9c0..199ee7ebf89 100644 --- a/analysis/decompiled/decompiler-to-file-stubs/tests/org/jetbrains/kotlin/analysis/decompiler/stub/files/AbstractClsStubBuilderTest.kt +++ b/analysis/decompiled/decompiler-to-file-stubs/tests/org/jetbrains/kotlin/analysis/decompiler/stub/files/AbstractClsStubBuilderTest.kt @@ -149,7 +149,7 @@ private data class TestData( } } -private object DummyFileAttributeService : FileAttributeService { +object DummyFileAttributeService : FileAttributeService { override fun write(file: VirtualFile, id: String, value: T, writeValueFun: (DataOutput, T) -> Unit): CachedAttributeData { return CachedAttributeData(value, 0) } diff --git a/analysis/symbol-light-classes/build.gradle.kts b/analysis/symbol-light-classes/build.gradle.kts index 349cfb9c587..3055168671b 100644 --- a/analysis/symbol-light-classes/build.gradle.kts +++ b/analysis/symbol-light-classes/build.gradle.kts @@ -16,6 +16,7 @@ dependencies { implementation(intellijCore()) testImplementation(project(":analysis:decompiled:decompiler-to-file-stubs")) + testImplementation(projectTests(":analysis:decompiled:decompiler-to-file-stubs")) testImplementation(projectTests(":analysis:analysis-api-impl-base")) testImplementation(projectTests(":analysis:analysis-api-fir")) } diff --git a/analysis/symbol-light-classes/tests/org/jetbrains/kotlin/light/classes/symbol/decompiled/service/SymbolLightClassesrFrontendApiTestConfiguratorService.kt b/analysis/symbol-light-classes/tests/org/jetbrains/kotlin/light/classes/symbol/decompiled/service/SymbolLightClassesrFrontendApiTestConfiguratorService.kt index b8c6da53e8e..0fbe20191b9 100644 --- a/analysis/symbol-light-classes/tests/org/jetbrains/kotlin/light/classes/symbol/decompiled/service/SymbolLightClassesrFrontendApiTestConfiguratorService.kt +++ b/analysis/symbol-light-classes/tests/org/jetbrains/kotlin/light/classes/symbol/decompiled/service/SymbolLightClassesrFrontendApiTestConfiguratorService.kt @@ -10,7 +10,6 @@ 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 @@ -19,13 +18,11 @@ import org.jetbrains.kotlin.analysis.api.impl.barebone.test.FrontendApiTestConfi 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.analysis.decompiler.stub.files.DummyFileAttributeService 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) { @@ -56,13 +53,3 @@ object SymbolLightClassesForLibraryFrontendApiTestConfiguratorService : Frontend FirFrontendApiTestConfiguratorService.doOutOfBlockModification(file) } } - -private object DummyFileAttributeService : FileAttributeService { - override fun write(file: VirtualFile, id: String, value: T, writeValueFun: (DataOutput, T) -> Unit): CachedAttributeData { - return CachedAttributeData(value, 0) - } - - override fun read(file: VirtualFile, id: String, readValueFun: (DataInput) -> T): CachedAttributeData? { - return null - } -} diff --git a/plugins/scripting/scripting-compiler-impl/src/org/jetbrains/kotlin/scripting/resolve/LazyScriptDescriptor.kt b/plugins/scripting/scripting-compiler-impl/src/org/jetbrains/kotlin/scripting/resolve/LazyScriptDescriptor.kt index 156b4d2fefe..0d69ed449cb 100644 --- a/plugins/scripting/scripting-compiler-impl/src/org/jetbrains/kotlin/scripting/resolve/LazyScriptDescriptor.kt +++ b/plugins/scripting/scripting-compiler-impl/src/org/jetbrains/kotlin/scripting/resolve/LazyScriptDescriptor.kt @@ -42,6 +42,7 @@ import org.jetbrains.kotlin.resolve.scopes.utils.addImportingScope import org.jetbrains.kotlin.resolve.source.toSourceElement import org.jetbrains.kotlin.scripting.definitions.* import org.jetbrains.kotlin.types.TypeSubstitutor +import org.jetbrains.kotlin.types.Variance import org.jetbrains.kotlin.types.typeUtil.isNothing import org.jetbrains.kotlin.types.typeUtil.isUnit import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstanceOrNull @@ -328,7 +329,7 @@ class LazyScriptDescriptor( ) val earlierScriptsParameter = if (isReplScript) { - createValueParameter(Name.special("") to builtIns.array.defaultType) + createValueParameter(Name.special("") to builtIns.getArrayType(Variance.INVARIANT, builtIns.anyType)) } else null val explicitParameters = baseExplicitParameters.map { it.copy(constructorDescriptor, it.name, paramsIndexBase++) } diff --git a/plugins/scripting/scripting-ide-services-test/build.gradle.kts b/plugins/scripting/scripting-ide-services-test/build.gradle.kts index 8f4893543be..283b7afa784 100644 --- a/plugins/scripting/scripting-ide-services-test/build.gradle.kts +++ b/plugins/scripting/scripting-ide-services-test/build.gradle.kts @@ -29,6 +29,10 @@ dependencies { testImplementation(commonDependency("org.jetbrains.kotlinx", "kotlinx-coroutines-core")) testImplementation(commonDependency("org.jetbrains.kotlinx", "kotlinx-coroutines-core-jvm")) testImplementation(project(":kotlin-reflect")) + testImplementation(project(":analysis:decompiled:decompiler-to-psi")) + testImplementation(project(":analysis:decompiled:decompiler-to-file-stubs")) + testImplementation(intellijCore()) + testImplementation(projectTests(":analysis:decompiled:decompiler-to-file-stubs")) testRuntimeOnly(project(":kotlin-compiler")) testRuntimeOnly(commonDependency("org.jetbrains.intellij.deps", "trove4j")) testRuntimeOnly(project(":kotlin-scripting-ide-common")) { isTransitive = false } diff --git a/plugins/scripting/scripting-ide-services-test/test/org/jetbrains/kotlin/scripting/ide_services/JvmReplTest.kt b/plugins/scripting/scripting-ide-services-test/test/org/jetbrains/kotlin/scripting/ide_services/JvmReplTest.kt index ea5d6fd6441..222200a50db 100644 --- a/plugins/scripting/scripting-ide-services-test/test/org/jetbrains/kotlin/scripting/ide_services/JvmReplTest.kt +++ b/plugins/scripting/scripting-ide-services-test/test/org/jetbrains/kotlin/scripting/ide_services/JvmReplTest.kt @@ -5,18 +5,31 @@ package org.jetbrains.kotlin.scripting.ide_services +import com.intellij.mock.MockApplication +import com.intellij.openapi.application.ApplicationManager +import com.intellij.openapi.vfs.VirtualFileManager +import com.intellij.util.indexing.FileContentImpl import junit.framework.TestCase +import org.jetbrains.kotlin.analysis.decompiler.psi.KotlinClassFileDecompiler +import org.jetbrains.kotlin.analysis.decompiler.stub.file.ClsKotlinBinaryClassCache +import org.jetbrains.kotlin.analysis.decompiler.stub.file.FileAttributeService +import org.jetbrains.kotlin.analysis.decompiler.stub.files.DummyFileAttributeService import org.jetbrains.kotlin.cli.common.ExitCode import org.jetbrains.kotlin.cli.common.arguments.K2JVMCompilerArguments import org.jetbrains.kotlin.cli.common.messages.CompilerMessageLocationWithRange import org.jetbrains.kotlin.cli.common.messages.MessageCollector import org.jetbrains.kotlin.cli.jvm.K2JVMCompiler +import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment import org.jetbrains.kotlin.config.Services +import org.jetbrains.kotlin.scripting.compiler.plugin.impl.KJvmCompiledModuleInMemoryImpl import org.jetbrains.kotlin.scripting.ide_services.test_util.* import java.io.File -import kotlin.io.path.* +import kotlin.io.path.ExperimentalPathApi +import kotlin.io.path.createTempDirectory +import kotlin.io.path.invariantSeparatorsPathString import kotlin.reflect.full.isSubclassOf import kotlin.script.experimental.api.* +import kotlin.script.experimental.jvm.impl.KJvmCompiledModuleInMemory import kotlin.script.experimental.jvm.impl.KJvmCompiledScript import kotlin.script.experimental.jvm.jvm import kotlin.script.experimental.jvm.updateClasspath @@ -340,6 +353,28 @@ class JvmIdeServicesTest : TestCase() { } } + fun testReplScriptClassFileDecompilation() { + JvmTestRepl() + .use { repl -> + val compiledSnippet = checkCompile(repl, "10 + 10") + val snippetValue = compiledSnippet.get()!! + + val compiledModule = snippetValue.getCompiledModule() as KJvmCompiledModuleInMemoryImpl + val folder = saveCompiledOutput("repl-script-decompilation", compiledModule) + + val vFile = VirtualFileManager.getInstance().findFileByNioPath(folder.resolve("Line_0_simplescript.class").toPath())!! + val fileContent = FileContentImpl.createByFile(vFile) + + val application = ApplicationManager.getApplication() as MockApplication + KotlinCoreEnvironment.underApplicationLock { + registerDecompilerServices(application) + } + + val fileStub = KotlinClassFileDecompiler().stubBuilder.buildFileStub(fileContent) + assertNotNull(fileStub) + } + } + @OptIn(ExperimentalPathApi::class) companion object { private const val MODULE_PATH = "plugins/scripting/scripting-ide-services-test" @@ -366,6 +401,21 @@ class JvmIdeServicesTest : TestCase() { return CliCompilationResult(exitCode, jarPath) } + + private fun saveCompiledOutput(subfolder: String, module: KJvmCompiledModuleInMemory): File { + val folder = outputJarDir.resolve(subfolder).toFile() + module.compilerOutputFiles.forEach { (name, contents) -> + val file = folder.resolve(name) + file.parentFile.mkdirs() + file.writeBytes(contents) + } + return folder + } + + private fun registerDecompilerServices(application: MockApplication) { + application.registerService(ClsKotlinBinaryClassCache::class.java) + application.registerService(FileAttributeService::class.java, DummyFileAttributeService) + } } }