Configuration providers don't create configurations for common code
Remove special code that creates configurations
and patches them for common modules
This should be done via MultipleRunLocationsProvider EP
This commit is contained in:
+5
-18
@@ -12,7 +12,6 @@ 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
|
||||
@@ -21,13 +20,11 @@ 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<JUnitConfiguration>(JUnitConfigurationType.getInstance()) {
|
||||
@@ -86,20 +83,21 @@ class KotlinJUnitRunConfigurationProducer : RunConfigurationProducer<JUnitConfig
|
||||
return false
|
||||
}
|
||||
|
||||
val ktFile = leaf.containingFile as KtFile
|
||||
val module = location.module ?: return false
|
||||
|
||||
val targetPlatform = TargetPlatformDetector.getPlatform(ktFile)
|
||||
if (targetPlatform != JvmPlatform && targetPlatform != TargetPlatform.Common) {
|
||||
val targetPlatform = TargetPlatformDetector.getPlatform(module)
|
||||
if (targetPlatform != JvmPlatform) {
|
||||
return false
|
||||
}
|
||||
|
||||
configuration.setModule(module)
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
@@ -109,23 +107,12 @@ class KotlinJUnitRunConfigurationProducer : RunConfigurationProducer<JUnitConfig
|
||||
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 ->
|
||||
|
||||
+180
@@ -0,0 +1,180 @@
|
||||
/*
|
||||
* 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<JUnitConfiguration>(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<PsiElement>
|
||||
): 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<KtClass>(false)
|
||||
if (!ktClass.isJUnitTestClass()) {
|
||||
ktClass = getTestClassInFile(containingFile)
|
||||
}
|
||||
return ktClass?.toLightClass()
|
||||
}
|
||||
|
||||
fun getTestMethodLocation(leaf: PsiElement): Location<PsiMethod>? {
|
||||
val function = leaf.getParentOfType<KtNamedFunction>(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<KtClass>().singleOrNull { it.isJUnitTestClass() }
|
||||
}
|
||||
}
|
||||
+180
@@ -0,0 +1,180 @@
|
||||
/*
|
||||
* 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<JUnitConfiguration>(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<PsiElement>
|
||||
): 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<KtClass>(false)
|
||||
if (!ktClass.isJUnitTestClass()) {
|
||||
ktClass = getTestClassInFile(containingFile)
|
||||
}
|
||||
return ktClass?.toLightClass()
|
||||
}
|
||||
|
||||
fun getTestMethodLocation(leaf: PsiElement): Location<PsiMethod>? {
|
||||
val function = leaf.getParentOfType<KtNamedFunction>(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<KtClass>().singleOrNull { it.isJUnitTestClass() }
|
||||
}
|
||||
}
|
||||
@@ -19,7 +19,6 @@ package org.jetbrains.kotlin.idea.run
|
||||
import com.intellij.execution.Location
|
||||
import com.intellij.execution.actions.ConfigurationContext
|
||||
import com.intellij.execution.actions.RunConfigurationProducer
|
||||
import com.intellij.openapi.module.Module
|
||||
import com.intellij.openapi.project.DumbService
|
||||
import com.intellij.openapi.util.Ref
|
||||
import com.intellij.psi.PsiElement
|
||||
@@ -28,13 +27,9 @@ import com.intellij.psi.util.PsiTreeUtil
|
||||
import org.jetbrains.kotlin.asJava.toLightClass
|
||||
import org.jetbrains.kotlin.fileClasses.javaFileFacadeFqName
|
||||
import org.jetbrains.kotlin.idea.MainFunctionDetector
|
||||
import org.jetbrains.kotlin.idea.caches.project.implementingModules
|
||||
import org.jetbrains.kotlin.idea.caches.resolve.resolveToDescriptorIfAny
|
||||
import org.jetbrains.kotlin.idea.project.TargetPlatformDetector
|
||||
import org.jetbrains.kotlin.idea.project.platform
|
||||
import org.jetbrains.kotlin.idea.util.ProjectRootsUtil
|
||||
import org.jetbrains.kotlin.platform.impl.isCommon
|
||||
import org.jetbrains.kotlin.platform.impl.isJvm
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
import org.jetbrains.kotlin.psi.psiUtil.getParentOfType
|
||||
import org.jetbrains.kotlin.resolve.jvm.platform.JvmPlatform
|
||||
@@ -47,7 +42,7 @@ class KotlinRunConfigurationProducer : RunConfigurationProducer<KotlinRunConfigu
|
||||
sourceElement: Ref<PsiElement>): Boolean {
|
||||
val location = context.location ?: return false
|
||||
val module = location.module ?: return false
|
||||
val container = getEntryPointContainer(location)
|
||||
val container = getEntryPointContainer(location) ?: return false
|
||||
val startClassFQName = getStartClassFqName(container) ?: return false
|
||||
|
||||
configuration.setModule(module)
|
||||
@@ -63,7 +58,7 @@ class KotlinRunConfigurationProducer : RunConfigurationProducer<KotlinRunConfigu
|
||||
|
||||
val module = location.module ?: return null
|
||||
|
||||
if (TargetPlatformDetector.getPlatform(module) !is JvmPlatform && module.findJvmImplementationModule() == null) {
|
||||
if (TargetPlatformDetector.getPlatform(module) !is JvmPlatform) {
|
||||
return null
|
||||
}
|
||||
val locationElement = location.psiElement
|
||||
@@ -72,7 +67,8 @@ class KotlinRunConfigurationProducer : RunConfigurationProducer<KotlinRunConfigu
|
||||
}
|
||||
|
||||
override fun isConfigurationFromContext(configuration: KotlinRunConfiguration, context: ConfigurationContext): Boolean {
|
||||
val startClassFQName = getStartClassFqName(getEntryPointContainer(context.location)) ?: return false
|
||||
val entryPointContainer = getEntryPointContainer(context.location) ?: return false
|
||||
val startClassFQName = getStartClassFqName(entryPointContainer) ?: return false
|
||||
|
||||
return configuration.runClass == startClassFQName &&
|
||||
context.module == configuration.configurationModule.module
|
||||
@@ -98,8 +94,7 @@ class KotlinRunConfigurationProducer : RunConfigurationProducer<KotlinRunConfigu
|
||||
return null
|
||||
}
|
||||
|
||||
fun getStartClassFqName(container: KtDeclarationContainer?): String? = when(container) {
|
||||
null -> null
|
||||
fun getStartClassFqName(container: KtDeclarationContainer): String? = when(container) {
|
||||
is KtFile -> container.javaFileFacadeFqName.asString()
|
||||
is KtClassOrObject -> {
|
||||
if (!container.isValid) {
|
||||
@@ -126,8 +121,3 @@ class KotlinRunConfigurationProducer : RunConfigurationProducer<KotlinRunConfigu
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
fun Module.findJvmImplementationModule(): Module? {
|
||||
if (!platform.isCommon) return null
|
||||
return implementingModules.firstOrNull { it.platform.isJvm }
|
||||
}
|
||||
|
||||
+133
@@ -0,0 +1,133 @@
|
||||
/*
|
||||
* Copyright 2010-2015 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.idea.run
|
||||
|
||||
import com.intellij.execution.Location
|
||||
import com.intellij.execution.actions.ConfigurationContext
|
||||
import com.intellij.execution.actions.RunConfigurationProducer
|
||||
import com.intellij.openapi.module.Module
|
||||
import com.intellij.openapi.project.DumbService
|
||||
import com.intellij.openapi.util.Ref
|
||||
import com.intellij.psi.PsiElement
|
||||
import com.intellij.psi.util.ClassUtil
|
||||
import com.intellij.psi.util.PsiTreeUtil
|
||||
import org.jetbrains.kotlin.asJava.toLightClass
|
||||
import org.jetbrains.kotlin.fileClasses.javaFileFacadeFqName
|
||||
import org.jetbrains.kotlin.idea.MainFunctionDetector
|
||||
import org.jetbrains.kotlin.idea.caches.project.implementingModules
|
||||
import org.jetbrains.kotlin.idea.caches.resolve.resolveToDescriptorIfAny
|
||||
import org.jetbrains.kotlin.idea.project.TargetPlatformDetector
|
||||
import org.jetbrains.kotlin.idea.project.platform
|
||||
import org.jetbrains.kotlin.idea.util.ProjectRootsUtil
|
||||
import org.jetbrains.kotlin.platform.impl.isCommon
|
||||
import org.jetbrains.kotlin.platform.impl.isJvm
|
||||
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<KotlinRunConfiguration>(KotlinRunConfigurationType.getInstance()) {
|
||||
|
||||
override fun setupConfigurationFromContext(configuration: KotlinRunConfiguration,
|
||||
context: ConfigurationContext,
|
||||
sourceElement: Ref<PsiElement>): 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 { 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<KtClass>(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 }
|
||||
}
|
||||
+133
@@ -0,0 +1,133 @@
|
||||
/*
|
||||
* Copyright 2010-2015 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.idea.run
|
||||
|
||||
import com.intellij.execution.Location
|
||||
import com.intellij.execution.actions.ConfigurationContext
|
||||
import com.intellij.execution.actions.RunConfigurationProducer
|
||||
import com.intellij.openapi.module.Module
|
||||
import com.intellij.openapi.project.DumbService
|
||||
import com.intellij.openapi.util.Ref
|
||||
import com.intellij.psi.PsiElement
|
||||
import com.intellij.psi.util.ClassUtil
|
||||
import com.intellij.psi.util.PsiTreeUtil
|
||||
import org.jetbrains.kotlin.asJava.toLightClass
|
||||
import org.jetbrains.kotlin.fileClasses.javaFileFacadeFqName
|
||||
import org.jetbrains.kotlin.idea.MainFunctionDetector
|
||||
import org.jetbrains.kotlin.idea.caches.project.implementingModules
|
||||
import org.jetbrains.kotlin.idea.caches.resolve.resolveToDescriptorIfAny
|
||||
import org.jetbrains.kotlin.idea.project.TargetPlatformDetector
|
||||
import org.jetbrains.kotlin.idea.project.platform
|
||||
import org.jetbrains.kotlin.idea.util.ProjectRootsUtil
|
||||
import org.jetbrains.kotlin.platform.impl.isCommon
|
||||
import org.jetbrains.kotlin.platform.impl.isJvm
|
||||
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<KotlinRunConfiguration>(KotlinRunConfigurationType.getInstance()) {
|
||||
|
||||
override fun setupConfigurationFromContext(configuration: KotlinRunConfiguration,
|
||||
context: ConfigurationContext,
|
||||
sourceElement: Ref<PsiElement>): 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 { 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<KtClass>(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 }
|
||||
}
|
||||
Reference in New Issue
Block a user