From 71d640f3f89121dd485ab88fe1b608e5e9b0f8c8 Mon Sep 17 00:00:00 2001 From: "Pavel V. Talanov" Date: Thu, 20 Sep 2018 19:26:45 +0200 Subject: [PATCH] Improve kotlin jvm run config producers for 181 and as32 branches Drop KotlinJUnitRunConfigurationProducer, KotlinRunConfigurationProducer bunch files Extract differences in behaviour to 'jvmMppUtils.kt' Improve 'isConfigurationFromContext' checks for 181 and as32 (this prevents duplicate configurations being created) KotlinRunConfigurationProducer chooses corresponding jvm module for common code #KT-26886 Fixed --- ...otlinGradleTestRunConfigurationProducer.kt | 14 +- .../KotlinJUnitRunConfigurationProducer.kt | 35 ++-- ...KotlinJUnitRunConfigurationProducer.kt.181 | 180 ------------------ .../run/KotlinRunConfigurationProducer.kt | 15 +- .../run/KotlinRunConfigurationProducer.kt.181 | 135 ------------- .../jetbrains/kotlin/idea/run/jvmMppUtils.kt | 17 ++ .../kotlin/idea/run/jvmMppUtils.kt.181 | 22 +++ 7 files changed, 65 insertions(+), 353 deletions(-) delete mode 100644 idea/idea-jvm/src/org/jetbrains/kotlin/idea/run/KotlinJUnitRunConfigurationProducer.kt.181 delete mode 100644 idea/idea-jvm/src/org/jetbrains/kotlin/idea/run/KotlinRunConfigurationProducer.kt.181 create mode 100644 idea/idea-jvm/src/org/jetbrains/kotlin/idea/run/jvmMppUtils.kt create mode 100644 idea/idea-jvm/src/org/jetbrains/kotlin/idea/run/jvmMppUtils.kt.181 diff --git a/idea/idea-gradle/src/org/jetbrains/kotlin/idea/run/KotlinGradleTestRunConfigurationProducer.kt b/idea/idea-gradle/src/org/jetbrains/kotlin/idea/run/KotlinGradleTestRunConfigurationProducer.kt index 177d4a202c8..da9d8dfa17b 100644 --- a/idea/idea-gradle/src/org/jetbrains/kotlin/idea/run/KotlinGradleTestRunConfigurationProducer.kt +++ b/idea/idea-gradle/src/org/jetbrains/kotlin/idea/run/KotlinGradleTestRunConfigurationProducer.kt @@ -29,8 +29,6 @@ import com.intellij.openapi.util.component2 import com.intellij.psi.PsiClass import com.intellij.psi.PsiElement import com.intellij.psi.PsiMethod -import org.jetbrains.kotlin.idea.project.platform -import org.jetbrains.kotlin.platform.impl.isJvm import org.jetbrains.plugins.gradle.execution.test.runner.TestClassGradleConfigurationProducer import org.jetbrains.plugins.gradle.execution.test.runner.TestMethodGradleConfigurationProducer import org.jetbrains.plugins.gradle.util.GradleConstants @@ -74,8 +72,7 @@ class KotlinTestClassGradleConfigurationProducer : TestClassGradleConfigurationP if (!IS_TEST_FRAMEWORK_PLUGIN_ENABLED) return false val contextLocation = context.location ?: return false - val module = context.module ?: return false - if (!module.platform.isJvm) return false + val module = context.module?.asJvmModule() ?: return false if (RunConfigurationProducer.getInstance(PatternConfigurationProducer::class.java).isMultipleElementsSelected(context)) { return false @@ -104,8 +101,7 @@ class KotlinTestClassGradleConfigurationProducer : TestClassGradleConfigurationP if (!IS_TEST_FRAMEWORK_PLUGIN_ENABLED) return false val leaf = context.location?.psiElement ?: return false - val module = context.module ?: return false - if (!module.platform.isJvm) return false + val module = context.module?.asJvmModule() ?: return false if (RunConfigurationProducer.getInstance(PatternConfigurationProducer::class.java).isMultipleElementsSelected(context)) { return false @@ -141,8 +137,7 @@ class KotlinTestMethodGradleConfigurationProducer : TestMethodGradleConfiguratio if (!IS_TEST_FRAMEWORK_PLUGIN_ENABLED) return false val contextLocation = context.location ?: return false - val module = context.module ?: return false - if (!module.platform.isJvm) return false + context.module?.asJvmModule() ?: return false if (RunConfigurationProducer.getInstance(PatternConfigurationProducer::class.java).isMultipleElementsSelected(context)) { return false @@ -168,8 +163,7 @@ class KotlinTestMethodGradleConfigurationProducer : TestMethodGradleConfiguratio } val contextLocation = context.location ?: return false - val module = context.module ?: return false - if (!module.platform.isJvm) return false + val module = context.module?.asJvmModule() ?: return false val psiMethod = getTestMethod(contextLocation.psiElement) ?: return false diff --git a/idea/idea-jvm/src/org/jetbrains/kotlin/idea/run/KotlinJUnitRunConfigurationProducer.kt b/idea/idea-jvm/src/org/jetbrains/kotlin/idea/run/KotlinJUnitRunConfigurationProducer.kt index a6dac68fb4c..7057f43ffb2 100644 --- a/idea/idea-jvm/src/org/jetbrains/kotlin/idea/run/KotlinJUnitRunConfigurationProducer.kt +++ b/idea/idea-jvm/src/org/jetbrains/kotlin/idea/run/KotlinJUnitRunConfigurationProducer.kt @@ -11,21 +11,21 @@ import com.intellij.execution.actions.ConfigurationFromContext import com.intellij.execution.actions.RunConfigurationProducer import com.intellij.execution.configurations.ModuleBasedConfiguration import com.intellij.execution.junit.* +import com.intellij.openapi.module.Module import com.intellij.openapi.project.DumbService +import com.intellij.openapi.roots.ModuleRootManager import com.intellij.openapi.util.Ref import com.intellij.psi.PsiClass import com.intellij.psi.PsiElement import com.intellij.psi.PsiMethod import com.intellij.psi.util.PsiTreeUtil import org.jetbrains.kotlin.asJava.toLightClass -import org.jetbrains.kotlin.idea.project.TargetPlatformDetector import org.jetbrains.kotlin.idea.util.ProjectRootsUtil import org.jetbrains.kotlin.psi.KtClass import org.jetbrains.kotlin.psi.KtFile import org.jetbrains.kotlin.psi.KtFunction import org.jetbrains.kotlin.psi.KtNamedFunction import org.jetbrains.kotlin.psi.psiUtil.getParentOfType -import org.jetbrains.kotlin.resolve.jvm.platform.JvmPlatform class KotlinJUnitRunConfigurationProducer : RunConfigurationProducer(JUnitConfigurationType.getInstance()) { override fun shouldReplace(self: ConfigurationFromContext, other: ConfigurationFromContext): Boolean { @@ -62,7 +62,7 @@ class KotlinJUnitRunConfigurationProducer : RunConfigurationProducer).configurationModule.module val configurationModule = configuration.configurationModule.module - return configurationModule == context.location?.module || configurationModule == predefinedModule + return configurationModule == context.location?.module?.asJvmModule() || configurationModule == predefinedModule } override fun setupConfigurationFromContext( @@ -74,6 +74,7 @@ class KotlinJUnitRunConfigurationProducer : RunConfigurationProducer diff --git a/idea/idea-jvm/src/org/jetbrains/kotlin/idea/run/KotlinJUnitRunConfigurationProducer.kt.181 b/idea/idea-jvm/src/org/jetbrains/kotlin/idea/run/KotlinJUnitRunConfigurationProducer.kt.181 deleted file mode 100644 index 3ee88706f4f..00000000000 --- a/idea/idea-jvm/src/org/jetbrains/kotlin/idea/run/KotlinJUnitRunConfigurationProducer.kt.181 +++ /dev/null @@ -1,180 +0,0 @@ -/* - * Copyright 2010-2018 JetBrains s.r.o. 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.idea.run - -import com.intellij.execution.* -import com.intellij.execution.actions.ConfigurationContext -import com.intellij.execution.actions.ConfigurationFromContext -import com.intellij.execution.actions.RunConfigurationProducer -import com.intellij.execution.configurations.ModuleBasedConfiguration -import com.intellij.execution.junit.* -import com.intellij.openapi.project.DumbService -import com.intellij.openapi.roots.ModuleRootManager -import com.intellij.openapi.util.Ref -import com.intellij.psi.PsiClass -import com.intellij.psi.PsiElement -import com.intellij.psi.PsiMethod -import com.intellij.psi.util.PsiTreeUtil -import org.jetbrains.kotlin.asJava.toLightClass -import org.jetbrains.kotlin.idea.project.TargetPlatformDetector -import org.jetbrains.kotlin.idea.util.ProjectRootsUtil -import org.jetbrains.kotlin.idea.util.module -import org.jetbrains.kotlin.psi.KtClass -import org.jetbrains.kotlin.psi.KtFile -import org.jetbrains.kotlin.psi.KtFunction -import org.jetbrains.kotlin.psi.KtNamedFunction -import org.jetbrains.kotlin.psi.psiUtil.getParentOfType -import org.jetbrains.kotlin.resolve.TargetPlatform -import org.jetbrains.kotlin.resolve.jvm.platform.JvmPlatform - -class KotlinJUnitRunConfigurationProducer : RunConfigurationProducer(JUnitConfigurationType.getInstance()) { - override fun shouldReplace(self: ConfigurationFromContext, other: ConfigurationFromContext): Boolean { - return other.isProducedBy(JUnitConfigurationProducer::class.java) || other.isProducedBy(PatternConfigurationProducer::class.java) - } - - override fun isConfigurationFromContext( - configuration: JUnitConfiguration, - context: ConfigurationContext - ): Boolean { - if (RunConfigurationProducer.getInstance(PatternConfigurationProducer::class.java).isMultipleElementsSelected(context)) { - return false - } - - val leaf = context.location?.psiElement ?: return false - val methodLocation = getTestMethodLocation(leaf) - val testClass = getTestClass(leaf) - val testObject = configuration.testObject - - if (!testObject.isConfiguredByElement(configuration, testClass, methodLocation?.psiElement, null, null)) { - return false - } - - return settingsMatchTemplate(configuration, context) - } - - // copied from JUnitConfigurationProducer in IDEA - private fun settingsMatchTemplate(configuration: JUnitConfiguration, context: ConfigurationContext): Boolean { - val predefinedConfiguration = context.getOriginalConfiguration(JUnitConfigurationType.getInstance()) - - val vmParameters = (predefinedConfiguration as? CommonJavaRunConfigurationParameters)?.vmParameters - if (vmParameters != null && configuration.vmParameters != vmParameters) return false - - val template = RunManager.getInstance(configuration.project).getConfigurationTemplate(configurationFactory) - val predefinedModule = (template.configuration as ModuleBasedConfiguration<*>).configurationModule.module - val configurationModule = configuration.configurationModule.module - return configurationModule == context.location?.module || configurationModule == predefinedModule - } - - override fun setupConfigurationFromContext( - configuration: JUnitConfiguration, - context: ConfigurationContext, - sourceElement: Ref - ): Boolean { - if (DumbService.getInstance(context.project).isDumb) return false - - val location = context.location ?: return false - val leaf = location.psiElement - - if (!ProjectRootsUtil.isInProjectOrLibSource(leaf)) { - return false - } - - if (leaf.containingFile !is KtFile) { - return false - } - - val ktFile = leaf.containingFile as KtFile - - val targetPlatform = TargetPlatformDetector.getPlatform(ktFile) - if (targetPlatform != JvmPlatform && targetPlatform != TargetPlatform.Common) { - return false - } - - val methodLocation = getTestMethodLocation(leaf) - if (methodLocation != null) { - val originalModule = configuration.configurationModule.module - configuration.beMethodConfiguration(methodLocation) - configuration.restoreOriginalModule(originalModule) - JavaRunConfigurationExtensionManager.getInstance().extendCreatedConfiguration(configuration, location) - fixJdkForCommonModule(ktFile, configuration) - return true - } - - val testClass = getTestClass(leaf) - if (testClass != null) { - val originalModule = configuration.configurationModule.module - configuration.beClassConfiguration(testClass) - configuration.restoreOriginalModule(originalModule) - JavaRunConfigurationExtensionManager.getInstance().extendCreatedConfiguration(configuration, location) - fixJdkForCommonModule(ktFile, configuration) - return true - } - - return false - } - - private fun fixJdkForCommonModule(ktFile: KtFile, configuration: JUnitConfiguration) { - val implModule = ktFile.module?.findJvmImplementationModule() ?: return - val sdk = ModuleRootManager.getInstance(implModule).sdk - if (sdk != null) { - configuration.setModule(implModule) - configuration.isAlternativeJrePathEnabled = true - configuration.alternativeJrePath = sdk.homePath - } - } - - override fun onFirstRun(fromContext: ConfigurationFromContext, context: ConfigurationContext, performRunnable: Runnable) { - val leaf = fromContext.sourceElement - getTestClass(leaf)?.let { testClass -> - val fromContextSubstitute = object : ConfigurationFromContext() { - override fun getConfigurationSettings() = fromContext.configurationSettings - - override fun setConfigurationSettings(configurationSettings: RunnerAndConfigurationSettings) { - fromContext.configurationSettings = configurationSettings - } - - override fun getSourceElement() = testClass - } - // TODO: use TestClassConfigurationProducer when constructor becomes public - return object : AbstractTestClassConfigurationProducer(JUnitConfigurationType.getInstance()){} - .onFirstRun(fromContextSubstitute, context, performRunnable) - } - - super.onFirstRun(fromContext, context, performRunnable) - } - - companion object { - fun getTestClass(leaf: PsiElement): PsiClass? { - val containingFile = leaf.containingFile as? KtFile ?: return null - var ktClass = leaf.getParentOfType(false) - if (!ktClass.isJUnitTestClass()) { - ktClass = getTestClassInFile(containingFile) - } - return ktClass?.toLightClass() - } - - fun getTestMethodLocation(leaf: PsiElement): Location? { - val function = leaf.getParentOfType(false) ?: return null - val owner = PsiTreeUtil.getParentOfType(function, KtFunction::class.java, KtClass::class.java) - - if (owner is KtClass) { - val delegate = owner.toLightClass() ?: return null - val method = delegate.methods.firstOrNull() { it.navigationElement == function } ?: return null - val methodLocation = PsiLocation.fromPsiElement(method) - if (JUnitUtil.isTestMethod(methodLocation, false)) { - return methodLocation - } - } - return null - } - - private fun KtClass?.isJUnitTestClass() = - this?.toLightClass()?.let { JUnitUtil.isTestClass(it, false, true) } ?: false - - private fun getTestClassInFile(ktFile: KtFile) = - ktFile.declarations.filterIsInstance().singleOrNull { it.isJUnitTestClass() } - } -} diff --git a/idea/idea-jvm/src/org/jetbrains/kotlin/idea/run/KotlinRunConfigurationProducer.kt b/idea/idea-jvm/src/org/jetbrains/kotlin/idea/run/KotlinRunConfigurationProducer.kt index 7c004c37184..d2b20d1dc55 100644 --- a/idea/idea-jvm/src/org/jetbrains/kotlin/idea/run/KotlinRunConfigurationProducer.kt +++ b/idea/idea-jvm/src/org/jetbrains/kotlin/idea/run/KotlinRunConfigurationProducer.kt @@ -28,12 +28,10 @@ import org.jetbrains.kotlin.asJava.toLightClass import org.jetbrains.kotlin.fileClasses.javaFileFacadeFqName import org.jetbrains.kotlin.idea.MainFunctionDetector import org.jetbrains.kotlin.idea.caches.resolve.resolveToDescriptorIfAny -import org.jetbrains.kotlin.idea.project.TargetPlatformDetector import org.jetbrains.kotlin.idea.project.languageVersionSettings import org.jetbrains.kotlin.idea.util.ProjectRootsUtil import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.psiUtil.getParentOfType -import org.jetbrains.kotlin.resolve.jvm.platform.JvmPlatform import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode class KotlinRunConfigurationProducer : RunConfigurationProducer(KotlinRunConfigurationType.getInstance()) { @@ -42,7 +40,7 @@ class KotlinRunConfigurationProducer : RunConfigurationProducer): Boolean { val location = context.location ?: return false - val module = location.module ?: return false + val module = location.module?.asJvmModule() ?: return false val container = getEntryPointContainer(location) ?: return false val startClassFQName = getStartClassFqName(container) ?: return false @@ -57,14 +55,7 @@ class KotlinRunConfigurationProducer : RunConfigurationProducer(KotlinRunConfigurationType.getInstance()) { - - override fun setupConfigurationFromContext(configuration: KotlinRunConfiguration, - context: ConfigurationContext, - sourceElement: Ref): Boolean { - val location = context.location ?: return false - val module = location.module ?: return false - val container = getEntryPointContainer(location) - val startClassFQName = getStartClassFqName(container) ?: return false - - configuration.setModule(module) - configuration.runClass = startClassFQName - configuration.setGeneratedName() - - return true - } - - private fun getEntryPointContainer(location: Location<*>?): KtDeclarationContainer? { - if (location == null) return null - if (DumbService.getInstance(location.project).isDumb) return null - - val module = location.module ?: return null - - if (TargetPlatformDetector.getPlatform(module) !is JvmPlatform && module.findJvmImplementationModule() == null) { - return null - } - val locationElement = location.psiElement - - return getEntryPointContainer(locationElement) - } - - override fun isConfigurationFromContext(configuration: KotlinRunConfiguration, context: ConfigurationContext): Boolean { - val startClassFQName = getStartClassFqName(getEntryPointContainer(context.location)) ?: return false - - return configuration.runClass == startClassFQName && - context.module == configuration.configurationModule.module - } - - companion object { - fun getEntryPointContainer(locationElement: PsiElement): KtDeclarationContainer? { - val psiFile = locationElement.containingFile - if (!(psiFile is KtFile && ProjectRootsUtil.isInProjectOrLibSource(psiFile))) return null - - val mainFunctionDetector = - MainFunctionDetector(psiFile.languageVersionSettings) { it.resolveToDescriptorIfAny(BodyResolveMode.FULL) } - - var currentElement = locationElement.declarationContainer(false) - while (currentElement != null) { - var entryPointContainer = currentElement - if (entryPointContainer is KtClass) { - entryPointContainer = entryPointContainer.companionObjects.singleOrNull() - } - if (entryPointContainer != null && mainFunctionDetector.hasMain(entryPointContainer.declarations)) return entryPointContainer - currentElement = (currentElement as PsiElement).declarationContainer(true) - } - - return null - } - - fun getStartClassFqName(container: KtDeclarationContainer?): String? = when(container) { - null -> null - is KtFile -> container.javaFileFacadeFqName.asString() - is KtClassOrObject -> { - if (!container.isValid) { - null - } - else if (container is KtObjectDeclaration && container.isCompanion()) { - val containerClass = container.getParentOfType(true) - containerClass?.toLightClass()?.let { ClassUtil.getJVMClassName(it) } - } - else { - container.toLightClass()?.let { ClassUtil.getJVMClassName(it) } - } - } - else -> throw IllegalArgumentException("Invalid entry-point container: " + (container as PsiElement).text) - } - - private fun PsiElement.declarationContainer(strict: Boolean): KtDeclarationContainer? { - val element = if (strict) - PsiTreeUtil.getParentOfType(this, KtClassOrObject::class.java, KtFile::class.java) - else - PsiTreeUtil.getNonStrictParentOfType(this, KtClassOrObject::class.java, KtFile::class.java) - return element as KtDeclarationContainer? - } - - } -} - -fun Module.findJvmImplementationModule(): Module? { - if (!platform.isCommon) return null - return implementingModules.firstOrNull { it.platform.isJvm } -} diff --git a/idea/idea-jvm/src/org/jetbrains/kotlin/idea/run/jvmMppUtils.kt b/idea/idea-jvm/src/org/jetbrains/kotlin/idea/run/jvmMppUtils.kt new file mode 100644 index 00000000000..0891fa1b53b --- /dev/null +++ b/idea/idea-jvm/src/org/jetbrains/kotlin/idea/run/jvmMppUtils.kt @@ -0,0 +1,17 @@ +/* + * Copyright 2010-2018 JetBrains s.r.o. 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.idea.run + +import com.intellij.openapi.module.Module +import org.jetbrains.kotlin.idea.project.platform +import org.jetbrains.kotlin.platform.impl.isJvm + +fun Module.asJvmModule(): Module? { + if (platform.isJvm) return this + + return null +} + diff --git a/idea/idea-jvm/src/org/jetbrains/kotlin/idea/run/jvmMppUtils.kt.181 b/idea/idea-jvm/src/org/jetbrains/kotlin/idea/run/jvmMppUtils.kt.181 new file mode 100644 index 00000000000..c0ea875cfc6 --- /dev/null +++ b/idea/idea-jvm/src/org/jetbrains/kotlin/idea/run/jvmMppUtils.kt.181 @@ -0,0 +1,22 @@ +/* + * Copyright 2010-2018 JetBrains s.r.o. 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.idea.run + +import com.intellij.openapi.module.Module +import org.jetbrains.kotlin.idea.caches.project.implementingModules +import org.jetbrains.kotlin.idea.project.platform +import org.jetbrains.kotlin.platform.impl.isCommon +import org.jetbrains.kotlin.platform.impl.isJvm + +fun Module.asJvmModule(): Module? { + if (platform.isJvm) return this + + if (platform.isCommon) { + return implementingModules.firstOrNull { it.platform.isJvm } + } + return null +} +