From c2316ca305194402b2b1ce6c906137cc94d9e661 Mon Sep 17 00:00:00 2001 From: Ilya Chernikov Date: Fri, 10 Jun 2022 14:27:00 +0200 Subject: [PATCH] Scripting: avoid definitions discovery when compiling regular kotlin If only regular kotlin .kt (and .java) files are compiled, do not register file extensions that may come from discovered script definitions. Since the discovery is lazy by itself, this should skip jars processing for regular compilation scenarios without scripts. #KT-47816 fixed --- .../cli/jvm/compiler/coreEnvironmentUtils.kt | 35 +++++++++++++++++-- .../CompilerConfigurationExtension.kt | 2 ++ .../ant/js/verbose/build.log.expected | 1 - .../ant/jvm/verbose/build.log.expected | 1 - .../src/main/kotlin/GreetScriptTemplate.kt | 12 +++++-- .../src/main/kotlin/GreetScriptTemplate.kt | 14 ++++++-- ...DefinitionsFromClasspathDiscoverySource.kt | 1 + .../scripting/definitions/definitions.kt | 2 ++ ...ScriptingCompilerConfigurationExtension.kt | 20 +++++++---- .../compiler/mixedCompilation/nonScript.kt | 4 +++ .../plugin/ScriptingWithCliCompilerTest.kt | 27 ++++++++++++++ 11 files changed, 102 insertions(+), 17 deletions(-) create mode 100644 plugins/scripting/scripting-compiler/testData/compiler/mixedCompilation/nonScript.kt diff --git a/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/compiler/coreEnvironmentUtils.kt b/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/compiler/coreEnvironmentUtils.kt index 78426681cdd..7eca96abd2d 100644 --- a/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/compiler/coreEnvironmentUtils.kt +++ b/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/compiler/coreEnvironmentUtils.kt @@ -5,6 +5,8 @@ package org.jetbrains.kotlin.cli.jvm.compiler +import com.intellij.ide.highlighter.JavaClassFileType +import com.intellij.ide.highlighter.JavaFileType import com.intellij.openapi.diagnostic.Logger import com.intellij.openapi.project.Project import com.intellij.openapi.vfs.StandardFileSystems @@ -19,9 +21,11 @@ import org.jetbrains.kotlin.cli.common.messages.MessageCollector import org.jetbrains.kotlin.config.CompilerConfiguration import org.jetbrains.kotlin.config.CompilerConfigurationKey import org.jetbrains.kotlin.config.JVMConfigurationKeys +import org.jetbrains.kotlin.extensions.CompilerConfigurationExtension import org.jetbrains.kotlin.extensions.PreprocessedFileCreator import org.jetbrains.kotlin.idea.KotlinFileType import org.jetbrains.kotlin.modules.Module +import org.jetbrains.kotlin.parsing.KotlinParserDefinition import org.jetbrains.kotlin.psi.KtFile import org.jetbrains.kotlin.resolve.multiplatform.isCommonSource import java.io.File @@ -43,6 +47,8 @@ inline fun List.forAllFiles( val virtualFileCreator = PreprocessedFileCreator(project) + var pluginsConfigured = false + for ((sourceRootPath, isCommon) in this) { val sourceRoot = File(sourceRootPath) val vFile = localFileSystem.findFileByPath(sourceRoot.normalize().path) @@ -59,9 +65,15 @@ inline fun List.forAllFiles( continue } - if (!vFile.isDirectory && vFile.extension != KotlinFileType.EXTENSION && vFile.fileType != KotlinFileType.INSTANCE) { - configuration.report(CompilerMessageSeverity.ERROR, "Source entry is not a Kotlin file: $sourceRootPath", reportLocation) - continue + if (!vFile.isDirectory && vFile.extension != KotlinFileType.EXTENSION) { + if (!pluginsConfigured) { + vFile.registerPluginsSuppliedExtensionsIfNeeded(project) + pluginsConfigured = true + } + if (vFile.fileType != KotlinFileType.INSTANCE) { + configuration.report(CompilerMessageSeverity.ERROR, "Source entry is not a Kotlin file: $sourceRootPath", reportLocation) + continue + } } for (file in sourceRoot.walkTopDown()) { @@ -69,12 +81,29 @@ inline fun List.forAllFiles( val virtualFile = localFileSystem.findFileByPath(file.absoluteFile.normalize().path)?.let(virtualFileCreator::create) if (virtualFile != null && processedFiles.add(virtualFile)) { + if (!pluginsConfigured) { + virtualFile.registerPluginsSuppliedExtensionsIfNeeded(project) + pluginsConfigured = true + } body(virtualFile, isCommon) } } } } +fun VirtualFile.registerPluginsSuppliedExtensionsIfNeeded(project: Project) { + if ( + extension == null || + extension == KotlinFileType.EXTENSION || + extension == JavaFileType.INSTANCE.defaultExtension || + extension == JavaClassFileType.INSTANCE.defaultExtension || + fileType == KotlinFileType.INSTANCE + ) return + for (extension in CompilerConfigurationExtension.getInstances(project)) { + extension.updateFileRegistry() + } +} + fun createSourceFilesFromSourceRoots( configuration: CompilerConfiguration, project: Project, diff --git a/compiler/frontend/src/org/jetbrains/kotlin/extensions/CompilerConfigurationExtension.kt b/compiler/frontend/src/org/jetbrains/kotlin/extensions/CompilerConfigurationExtension.kt index 14b9ebe74b4..60563230c82 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/extensions/CompilerConfigurationExtension.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/extensions/CompilerConfigurationExtension.kt @@ -15,4 +15,6 @@ interface CompilerConfigurationExtension { ) fun updateConfiguration(configuration: CompilerConfiguration) + + fun updateFileRegistry() {} } diff --git a/compiler/testData/integration/ant/js/verbose/build.log.expected b/compiler/testData/integration/ant/js/verbose/build.log.expected index 3547c07936c..47e94efe601 100644 --- a/compiler/testData/integration/ant/js/verbose/build.log.expected +++ b/compiler/testData/integration/ant/js/verbose/build.log.expected @@ -5,7 +5,6 @@ build: [kotlin2js] Compiling [[TestData]/root1] => [[Temp]/out.js] [kotlin2js] logging: using Kotlin home directory [KotlinProjectHome]/dist/kotlinc [kotlin2js] logging: exception on loading scripting plugin: java.lang.ClassNotFoundException: org.jetbrains.kotlin.scripting.compiler.plugin.ScriptingCompilerConfigurationComponentRegistrar -[kotlin2js] logging: configure scripting: Added template org.jetbrains.kotlin.mainKts.MainKtsScript from [[CompilerLib]/kotlin-main-kts.jar, [CompilerLib]/kotlin-reflect.jar, [CompilerLib]/kotlin-script-runtime.jar, [CompilerLib]/kotlin-stdlib.jar] [kotlin2js] logging: compiling source files: [TestData]/root1/foo.kt BUILD SUCCESSFUL diff --git a/compiler/testData/integration/ant/jvm/verbose/build.log.expected b/compiler/testData/integration/ant/jvm/verbose/build.log.expected index 01b50dabf9d..8b9e0dea68c 100644 --- a/compiler/testData/integration/ant/jvm/verbose/build.log.expected +++ b/compiler/testData/integration/ant/jvm/verbose/build.log.expected @@ -7,7 +7,6 @@ build: [kotlinc] logging: exception on loading scripting plugin: java.lang.ClassNotFoundException: org.jetbrains.kotlin.scripting.compiler.plugin.ScriptingCompilerConfigurationComponentRegistrar [kotlinc] logging: using JVM IR backend [kotlinc] logging: configuring the compilation environment - [kotlinc] logging: configure scripting: Added template org.jetbrains.kotlin.mainKts.MainKtsScript from [[CompilerLib]/kotlin-main-kts.jar, [CompilerLib]/kotlin-reflect.jar, [CompilerLib]/kotlin-script-runtime.jar, [CompilerLib]/kotlin-stdlib.jar] BUILD SUCCESSFUL Total time: [time] diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/scripting/script-template/src/main/kotlin/GreetScriptTemplate.kt b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/scripting/script-template/src/main/kotlin/GreetScriptTemplate.kt index 07d650b799e..dc13db8922a 100644 --- a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/scripting/script-template/src/main/kotlin/GreetScriptTemplate.kt +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/scripting/script-template/src/main/kotlin/GreetScriptTemplate.kt @@ -6,10 +6,18 @@ package org.jetbrains.kotlin.test import kotlin.script.experimental.annotations.* +import kotlin.script.experimental.api.ScriptCompilationConfiguration +import kotlin.script.experimental.api.isStandalone -@KotlinScript(fileExtension = "greet.kts") +@KotlinScript(fileExtension = "greet.kts", compilationConfiguration = GreetScriptDefinition::class) abstract class GreetScriptTemplate { fun greet(subject: String) { println("Hello, $subject!") } -} \ No newline at end of file +} + +object GreetScriptDefinition : ScriptCompilationConfiguration( + { + isStandalone(false) + } +) diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/scriptingCustomExtension/script-template/src/main/kotlin/GreetScriptTemplate.kt b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/scriptingCustomExtension/script-template/src/main/kotlin/GreetScriptTemplate.kt index 2283cc1d8e8..2d77bd5db10 100644 --- a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/scriptingCustomExtension/script-template/src/main/kotlin/GreetScriptTemplate.kt +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/scriptingCustomExtension/script-template/src/main/kotlin/GreetScriptTemplate.kt @@ -5,11 +5,19 @@ package org.jetbrains.kotlin.test -import kotlin.script.experimental.annotations.* +import kotlin.script.experimental.annotations.KotlinScript +import kotlin.script.experimental.api.ScriptCompilationConfiguration +import kotlin.script.experimental.api.isStandalone -@KotlinScript(fileExtension = "greet") +@KotlinScript(fileExtension = "greet", compilationConfiguration = GreetScriptDefinition::class) abstract class GreetScriptTemplate { fun greet(subject: String) { println("Hello, $subject!") } -} \ No newline at end of file +} + +object GreetScriptDefinition : ScriptCompilationConfiguration( + { + isStandalone(false) + } +) diff --git a/plugins/scripting/scripting-compiler-impl/src/org/jetbrains/kotlin/scripting/definitions/ScriptiDefinitionsFromClasspathDiscoverySource.kt b/plugins/scripting/scripting-compiler-impl/src/org/jetbrains/kotlin/scripting/definitions/ScriptiDefinitionsFromClasspathDiscoverySource.kt index 10135840370..92e8d81296f 100644 --- a/plugins/scripting/scripting-compiler-impl/src/org/jetbrains/kotlin/scripting/definitions/ScriptiDefinitionsFromClasspathDiscoverySource.kt +++ b/plugins/scripting/scripting-compiler-impl/src/org/jetbrains/kotlin/scripting/definitions/ScriptiDefinitionsFromClasspathDiscoverySource.kt @@ -39,6 +39,7 @@ class ScriptDefinitionsFromClasspathDiscoverySource( private const val MANIFEST_RESOURCE_NAME = "/META-INF/MANIFEST.MF" +@Suppress("unused") // TODO: remove if really unused fun discoverScriptTemplatesInClassLoader( classLoader: ClassLoader, hostConfiguration: ScriptingHostConfiguration, diff --git a/plugins/scripting/scripting-compiler-impl/src/org/jetbrains/kotlin/scripting/definitions/definitions.kt b/plugins/scripting/scripting-compiler-impl/src/org/jetbrains/kotlin/scripting/definitions/definitions.kt index 42c7c39ca9a..b581ea9c2ff 100644 --- a/plugins/scripting/scripting-compiler-impl/src/org/jetbrains/kotlin/scripting/definitions/definitions.kt +++ b/plugins/scripting/scripting-compiler-impl/src/org/jetbrains/kotlin/scripting/definitions/definitions.kt @@ -6,6 +6,7 @@ package org.jetbrains.kotlin.scripting.definitions import com.intellij.ide.highlighter.JavaClassFileType +import com.intellij.ide.highlighter.JavaFileType import com.intellij.openapi.application.ApplicationManager import com.intellij.openapi.fileTypes.FileTypeRegistry import com.intellij.openapi.project.Project @@ -56,6 +57,7 @@ fun findScriptDefinition(project: Project, script: SourceCode): ScriptDefinition fun VirtualFile.isNonScript(): Boolean = isDirectory || extension == KotlinFileType.EXTENSION || + extension == JavaFileType.INSTANCE.defaultExtension || extension == JavaClassFileType.INSTANCE.defaultExtension || !this.isKotlinFileType() diff --git a/plugins/scripting/scripting-compiler/src/org/jetbrains/kotlin/scripting/compiler/plugin/ScriptingCompilerConfigurationExtension.kt b/plugins/scripting/scripting-compiler/src/org/jetbrains/kotlin/scripting/compiler/plugin/ScriptingCompilerConfigurationExtension.kt index 8729826f22f..065445699cb 100644 --- a/plugins/scripting/scripting-compiler/src/org/jetbrains/kotlin/scripting/compiler/plugin/ScriptingCompilerConfigurationExtension.kt +++ b/plugins/scripting/scripting-compiler/src/org/jetbrains/kotlin/scripting/compiler/plugin/ScriptingCompilerConfigurationExtension.kt @@ -20,6 +20,7 @@ import org.jetbrains.kotlin.scripting.compiler.plugin.impl.reporter import org.jetbrains.kotlin.scripting.configuration.ScriptingConfigurationKeys import org.jetbrains.kotlin.scripting.definitions.* import java.io.File +import java.util.concurrent.atomic.AtomicBoolean import kotlin.script.experimental.host.ScriptingHostConfiguration class ScriptingCompilerConfigurationExtension( @@ -88,15 +89,20 @@ class ScriptingCompilerConfigurationExtension( if (scriptDefinitionProvider != null) { scriptDefinitionProvider.setScriptDefinitionsSources(configuration.getList(ScriptingConfigurationKeys.SCRIPT_DEFINITIONS_SOURCES)) scriptDefinitionProvider.setScriptDefinitions(configuration.getList(ScriptingConfigurationKeys.SCRIPT_DEFINITIONS)) + } + } + } - // Register new file extensions - val fileTypeRegistry = FileTypeRegistry.getInstance() as CoreFileTypeRegistry + override fun updateFileRegistry() { + val scriptDefinitionProvider = ScriptDefinitionProvider.getInstance(project) as? CliScriptDefinitionProvider + if (scriptDefinitionProvider != null) { + // Register new file extensions + val fileTypeRegistry = FileTypeRegistry.getInstance() as CoreFileTypeRegistry - scriptDefinitionProvider.getKnownFilenameExtensions().filter { - fileTypeRegistry.getFileTypeByExtension(it) != KotlinFileType.INSTANCE - }.forEach { - fileTypeRegistry.registerFileType(KotlinFileType.INSTANCE, it) - } + scriptDefinitionProvider.getKnownFilenameExtensions().filter { + fileTypeRegistry.getFileTypeByExtension(it) != KotlinFileType.INSTANCE + }.forEach { + fileTypeRegistry.registerFileType(KotlinFileType.INSTANCE, it) } } } diff --git a/plugins/scripting/scripting-compiler/testData/compiler/mixedCompilation/nonScript.kt b/plugins/scripting/scripting-compiler/testData/compiler/mixedCompilation/nonScript.kt new file mode 100644 index 00000000000..fb57e4d5807 --- /dev/null +++ b/plugins/scripting/scripting-compiler/testData/compiler/mixedCompilation/nonScript.kt @@ -0,0 +1,4 @@ + +fun main() { + println("OK") +} diff --git a/plugins/scripting/scripting-compiler/tests/org/jetbrains/kotlin/scripting/compiler/plugin/ScriptingWithCliCompilerTest.kt b/plugins/scripting/scripting-compiler/tests/org/jetbrains/kotlin/scripting/compiler/plugin/ScriptingWithCliCompilerTest.kt index 3b7e086a365..d2a6be121c2 100644 --- a/plugins/scripting/scripting-compiler/tests/org/jetbrains/kotlin/scripting/compiler/plugin/ScriptingWithCliCompilerTest.kt +++ b/plugins/scripting/scripting-compiler/tests/org/jetbrains/kotlin/scripting/compiler/plugin/ScriptingWithCliCompilerTest.kt @@ -240,6 +240,33 @@ class ScriptingWithCliCompilerTest { } } + @Test + fun testScriptMainKtsDiscovery() { + withTempDir { tmpdir -> + + fun compileSuccessfullyGetStdErr(fileArg: String): List { + val (_, err, ret) = captureOutErrRet { + CLITool.doMainNoExit( + K2JVMCompiler(), + arrayOf( + "-P", "plugin:kotlin.scripting:disable-script-definitions-autoloading=true", + "-cp", getMainKtsClassPath().joinToString(File.pathSeparator), "-d", tmpdir.path, "-verbose", fileArg) + ) + } + Assert.assertEquals(0, ret.code) + return err.linesSplitTrim() + } + + val loadMainKtsMessage = "logging: configure scripting: loading script definition class org.jetbrains.kotlin.mainKts.MainKtsScript using classpath" + + val res1 = compileSuccessfullyGetStdErr("$TEST_DATA_DIR/compiler/mixedCompilation/nonScript.kt") + Assert.assertTrue(res1.none { it.startsWith(loadMainKtsMessage) }) + + val res2 = compileSuccessfullyGetStdErr("$TEST_DATA_DIR/compiler/mixedCompilation/simpleScript.main.kts") + Assert.assertTrue(res2.any { it.startsWith(loadMainKtsMessage) }) + } + } + private fun getMainKtsClassPath(): List { return listOf( File("dist/kotlinc/lib/kotlin-main-kts.jar").also {