convert KotlinRunConfigurationProducer to new API, allowing it to coexist with KotlinJUnitRunConfigurationProducer correctly

#KT-2604 Fixed
This commit is contained in:
Dmitry Jemerov
2015-07-02 17:50:22 +02:00
committed by Nikolay Krasko
parent 9d650b6154
commit 49714d0817
2 changed files with 46 additions and 63 deletions
+1 -1
View File
@@ -391,7 +391,7 @@
<configurationType implementation="org.jetbrains.kotlin.idea.run.JetRunConfigurationType"/> <configurationType implementation="org.jetbrains.kotlin.idea.run.JetRunConfigurationType"/>
<configurationType implementation="org.jetbrains.kotlin.idea.k2jsrun.K2JSRunConfigurationType"/> <configurationType implementation="org.jetbrains.kotlin.idea.k2jsrun.K2JSRunConfigurationType"/>
<programRunner implementation="org.jetbrains.kotlin.idea.k2jsrun.K2JSBrowserProgramRunner"/> <programRunner implementation="org.jetbrains.kotlin.idea.k2jsrun.K2JSBrowserProgramRunner"/>
<configurationProducer implementation="org.jetbrains.kotlin.idea.run.KotlinRunConfigurationProducer"/> <runConfigurationProducer implementation="org.jetbrains.kotlin.idea.run.KotlinRunConfigurationProducer"/>
<codeInsight.lineMarkerProvider language="jet" implementationClass="org.jetbrains.kotlin.idea.highlighter.markers.KotlinLineMarkerProvider"/> <codeInsight.lineMarkerProvider language="jet" implementationClass="org.jetbrains.kotlin.idea.highlighter.markers.KotlinLineMarkerProvider"/>
<codeInsight.lineMarkerProvider language="jet" implementationClass="org.jetbrains.kotlin.idea.highlighter.KotlinRecursiveCallLineMarkerProvider"/> <codeInsight.lineMarkerProvider language="jet" implementationClass="org.jetbrains.kotlin.idea.highlighter.KotlinRecursiveCallLineMarkerProvider"/>
<codeInsight.lineMarkerProvider language="JAVA" <codeInsight.lineMarkerProvider language="JAVA"
@@ -19,13 +19,14 @@ package org.jetbrains.kotlin.idea.run
import com.intellij.execution.Location import com.intellij.execution.Location
import com.intellij.execution.RunnerAndConfigurationSettings import com.intellij.execution.RunnerAndConfigurationSettings
import com.intellij.execution.actions.ConfigurationContext import com.intellij.execution.actions.ConfigurationContext
import com.intellij.execution.actions.RunConfigurationProducer
import com.intellij.execution.junit.RuntimeConfigurationProducer import com.intellij.execution.junit.RuntimeConfigurationProducer
import com.intellij.openapi.module.Module import com.intellij.openapi.module.Module
import com.intellij.openapi.project.DumbService import com.intellij.openapi.project.DumbService
import com.intellij.openapi.util.Comparing import com.intellij.openapi.util.Comparing
import com.intellij.openapi.util.Ref
import com.intellij.openapi.util.text.StringUtil import com.intellij.openapi.util.text.StringUtil
import com.intellij.psi.PsiElement import com.intellij.psi.PsiElement
import com.intellij.psi.impl.ElementBase
import com.intellij.psi.util.PsiTreeUtil import com.intellij.psi.util.PsiTreeUtil
import com.intellij.util.NotNullFunction import com.intellij.util.NotNullFunction
import org.jetbrains.kotlin.descriptors.FunctionDescriptor import org.jetbrains.kotlin.descriptors.FunctionDescriptor
@@ -36,46 +37,38 @@ import org.jetbrains.kotlin.idea.util.ProjectRootsUtil
import org.jetbrains.kotlin.load.kotlin.PackageClassUtils import org.jetbrains.kotlin.load.kotlin.PackageClassUtils
import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.getParentOfType
public class KotlinRunConfigurationProducer : RuntimeConfigurationProducer(JetRunConfigurationType.getInstance()), Cloneable { public class KotlinRunConfigurationProducer : RunConfigurationProducer<JetRunConfiguration>(JetRunConfigurationType.getInstance()) {
override fun clone(): KotlinRunConfigurationProducer {
return super<RuntimeConfigurationProducer>.clone() as KotlinRunConfigurationProducer override fun setupConfigurationFromContext(configuration: JetRunConfiguration,
context: ConfigurationContext,
sourceElement: Ref<PsiElement>): Boolean {
val location = context.getLocation() ?: return false
val module = context.getModule() ?: return false
val container = getEntryPointContainer(location)
val startClassFQName = getStartClassFqName(container) ?: return false
setupConfigurationByQName(module, configuration, startClassFQName)
return true
} }
private var mySourceElement: PsiElement? = null private fun getStartClassFqName(container: JetDeclarationContainer?): FqName? = when(container) {
null -> null
override fun getSourceElement(): PsiElement? { is JetFile -> PackageClassUtils.getPackageClassFqName(container.getPackageFqName())
return mySourceElement is JetClassOrObject -> {
}
override fun createConfigurationByElement(location: Location<*>, configurationContext: ConfigurationContext): RunnerAndConfigurationSettings? {
val container = getEntryPointContainer(location) ?: return null
mySourceElement = container as PsiElement?
val startClassFQName = getStartClassFqName(container)
if (startClassFQName == null) return null
val module = location.getModule()
assert(module != null)
return createConfigurationByQName(module, configurationContext, startClassFQName)
}
private fun getStartClassFqName(container: JetDeclarationContainer?): FqName? {
if (container == null) return null
if (container is JetFile) return PackageClassUtils.getPackageClassFqName((container as JetFile?).getPackageFqName())
if (container is JetClassOrObject) {
if (container is JetObjectDeclaration && container.isCompanion()) { if (container is JetObjectDeclaration && container.isCompanion()) {
val containerClass = PsiTreeUtil.getParentOfType<JetClass>(container, javaClass<JetClass>()) val containerClass = container.getParentOfType<JetClass>(true)
return containerClass?.getFqName() containerClass?.getFqName()
} else {
container.getFqName()
} }
return container?.getFqName()
} }
throw IllegalArgumentException("Invalid entry-point container: " + (container as PsiElement?).getText()) else -> throw IllegalArgumentException("Invalid entry-point container: " + (container as PsiElement).getText())
} }
private fun getEntryPointContainer(location: Location<*>): JetDeclarationContainer? { private fun getEntryPointContainer(location: Location<*>?): JetDeclarationContainer? {
if (location == null) return null
if (DumbService.getInstance(location.getProject()).isDumb()) return null if (DumbService.getInstance(location.getProject()).isDumb()) return null
val module = location.getModule() ?: return null val module = location.getModule() ?: return null
@@ -88,51 +81,41 @@ public class KotlinRunConfigurationProducer : RuntimeConfigurationProducer(JetRu
if (!(psiFile is JetFile && ProjectRootsUtil.isInProjectOrLibSource(psiFile))) return null if (!(psiFile is JetFile && ProjectRootsUtil.isInProjectOrLibSource(psiFile))) return null
val resolutionFacade = psiFile.getResolutionFacade() val resolutionFacade = psiFile.getResolutionFacade()
val mainFunctionDetector = MainFunctionDetector(object : NotNullFunction<JetNamedFunction, FunctionDescriptor> { val mainFunctionDetector = MainFunctionDetector { resolutionFacade.resolveToDescriptor(it) as FunctionDescriptor }
override fun `fun`(function: JetNamedFunction): FunctionDescriptor {
return resolutionFacade.resolveToDescriptor(function) as FunctionDescriptor
}
})
var currentElement = PsiTreeUtil.getNonStrictParentOfType<PsiElement>(locationElement, javaClass<JetClassOrObject>(), javaClass<JetFile>()) as JetDeclarationContainer var currentElement = locationElement.declarationContainer(false)
while (currentElement != null) { while (currentElement != null) {
var entryPointContainer = currentElement var entryPointContainer = currentElement
if (entryPointContainer is JetClass) { if (entryPointContainer is JetClass) {
entryPointContainer = entryPointContainer.getCompanionObjects().singleOrNull() as JetDeclarationContainer entryPointContainer = entryPointContainer.getCompanionObjects().singleOrNull()
} }
if (entryPointContainer != null && mainFunctionDetector.hasMain(entryPointContainer.getDeclarations())) return entryPointContainer if (entryPointContainer != null && mainFunctionDetector.hasMain(entryPointContainer.getDeclarations())) return entryPointContainer
currentElement = PsiTreeUtil.getParentOfType<PsiElement>(currentElement as PsiElement?, javaClass<JetClassOrObject>(), javaClass<JetFile>()) as JetDeclarationContainer currentElement = (currentElement as PsiElement).declarationContainer(true)
} }
return null return null
} }
private fun createConfigurationByQName(module: Module, context: ConfigurationContext, fqName: FqName): RunnerAndConfigurationSettings { private fun PsiElement.declarationContainer(strict: Boolean): JetDeclarationContainer? {
val settings = cloneTemplateConfiguration(module.getProject(), context) val element = if (strict)
val configuration = settings.getConfiguration() as JetRunConfiguration PsiTreeUtil.getParentOfType(this, javaClass<JetClassOrObject>(), javaClass<JetFile>())
else
PsiTreeUtil.getNonStrictParentOfType(this, javaClass<JetClassOrObject>(), javaClass<JetFile>())
return element as JetDeclarationContainer?
}
private fun setupConfigurationByQName(module: Module,
configuration: JetRunConfiguration,
fqName: FqName) {
configuration.setModule(module) configuration.setModule(module)
configuration.setName(StringUtil.trimEnd(fqName.asString(), "." + PackageClassUtils.getPackageClassName(fqName))) configuration.setName(StringUtil.trimEnd(fqName.asString(), "." + PackageClassUtils.getPackageClassName(fqName)))
configuration.setRunClass(fqName.asString()) configuration.setRunClass(fqName.asString())
return settings
} }
override fun findExistingByElement(location: Location<*>?, existingConfigurations: List<RunnerAndConfigurationSettings>, context: ConfigurationContext?): RunnerAndConfigurationSettings? { override fun isConfigurationFromContext(configuration: JetRunConfiguration, context: ConfigurationContext): Boolean {
val startClassFQName = getStartClassFqName(getEntryPointContainer(location)) ?: return null val startClassFQName = getStartClassFqName(getEntryPointContainer(context.getLocation())) ?: return false
for (existingConfiguration in existingConfigurations) { return configuration.getRunClass() == startClassFQName.asString() &&
if (existingConfiguration.getType() is JetRunConfigurationType) { context.getModule() == configuration.getConfigurationModule().getModule()
val jetConfiguration = existingConfiguration.getConfiguration() as JetRunConfiguration
if (Comparing.equal(jetConfiguration.getRunClass(), startClassFQName.asString())) {
if (Comparing.equal<Module>(location!!.getModule(), jetConfiguration.getConfigurationModule().getModule())) {
return existingConfiguration
}
}
}
}
return null
}
override fun compareTo(o: Any?): Int {
return RuntimeConfigurationProducer.PREFERED
} }
} }