Implement test icon provider for 'native' platform
This commit is contained in:
@@ -11,28 +11,21 @@ import com.intellij.execution.actions.RunConfigurationProducer
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.openapi.roots.libraries.Library
|
||||
import com.intellij.openapi.util.io.FileUtil
|
||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.ClassDescriptorWithResolutionScopes
|
||||
import com.intellij.util.SmartList
|
||||
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
||||
import org.jetbrains.kotlin.gradle.KotlinPlatform
|
||||
import org.jetbrains.kotlin.idea.compiler.configuration.Kotlin2JsCompilerArgumentsHolder
|
||||
import org.jetbrains.kotlin.idea.framework.JSLibraryKind
|
||||
import org.jetbrains.kotlin.idea.framework.JSLibraryStdDescription
|
||||
import org.jetbrains.kotlin.idea.framework.JsLibraryStdDetectionUtil
|
||||
import org.jetbrains.kotlin.idea.highlighter.KotlinTestRunLineMarkerContributor.Companion.getTestStateIcon
|
||||
import org.jetbrains.kotlin.idea.js.KotlinJSRunConfigurationData
|
||||
import org.jetbrains.kotlin.idea.js.KotlinJSRunConfigurationDataProvider
|
||||
import org.jetbrains.kotlin.idea.platform.IdePlatformKindTooling
|
||||
import org.jetbrains.kotlin.idea.platform.getGenericTestIcon
|
||||
import org.jetbrains.kotlin.idea.run.multiplatform.KotlinMultiplatformRunLocationsProvider
|
||||
import org.jetbrains.kotlin.idea.util.string.joinWithEscape
|
||||
import org.jetbrains.kotlin.js.resolve.JsResolverForModuleFactory
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.platform.impl.JsIdePlatformKind
|
||||
import org.jetbrains.kotlin.psi.KtClassOrObject
|
||||
import org.jetbrains.kotlin.psi.KtFunction
|
||||
import org.jetbrains.kotlin.psi.KtNamedDeclaration
|
||||
import org.jetbrains.kotlin.psi.KtNamedFunction
|
||||
import org.jetbrains.kotlin.psi.psiUtil.containingClassOrObject
|
||||
import org.jetbrains.kotlin.psi.psiUtil.parentsWithSelf
|
||||
import org.jetbrains.kotlin.utils.PathUtil
|
||||
import org.jetbrains.kotlin.utils.ifEmpty
|
||||
import javax.swing.Icon
|
||||
@@ -40,9 +33,6 @@ import javax.swing.Icon
|
||||
class JsIdePlatformKindTooling : IdePlatformKindTooling() {
|
||||
companion object {
|
||||
private const val MAVEN_OLD_JS_STDLIB_ID = "kotlin-js-library"
|
||||
|
||||
private val TEST_FQ_NAME = FqName("kotlin.test.Test")
|
||||
private val IGNORE_FQ_NAME = FqName("kotlin.test.Ignore")
|
||||
}
|
||||
|
||||
override val kind = JsIdePlatformKind
|
||||
@@ -61,39 +51,26 @@ class JsIdePlatformKindTooling : IdePlatformKindTooling() {
|
||||
}
|
||||
|
||||
override fun getTestIcon(declaration: KtNamedDeclaration, descriptor: DeclarationDescriptor): Icon? {
|
||||
if (!descriptor.isTest()) return null
|
||||
return getGenericTestIcon(declaration, descriptor) {
|
||||
val contexts by lazy { computeConfigurationContexts(declaration) }
|
||||
|
||||
val contexts by lazy { computeConfigurationContexts(declaration) }
|
||||
val runConfigData = RunConfigurationProducer
|
||||
.getProducers(declaration.project)
|
||||
.asSequence()
|
||||
.filterIsInstance<KotlinJSRunConfigurationDataProvider<*>>()
|
||||
.filter { it.isForTests }
|
||||
.flatMap { provider -> contexts.map { context -> provider.getConfigurationData(context) } }
|
||||
.firstOrNull { it != null }
|
||||
?: return@getGenericTestIcon null
|
||||
|
||||
val runConfigData = RunConfigurationProducer
|
||||
.getProducers(declaration.project)
|
||||
.asSequence()
|
||||
.filterIsInstance<KotlinJSRunConfigurationDataProvider<*>>()
|
||||
.filter { it.isForTests }
|
||||
.flatMap { provider -> contexts.map { context -> provider.getConfigurationData(context) } }
|
||||
.firstOrNull { it != null } ?: return null
|
||||
val location = if (runConfigData is KotlinJSRunConfigurationData) {
|
||||
FileUtil.toSystemDependentName(runConfigData.jsOutputFilePath)
|
||||
} else {
|
||||
declaration.containingKtFile.packageFqName.asString()
|
||||
}
|
||||
|
||||
val locations = ArrayList<String>()
|
||||
|
||||
locations += FileUtil.toSystemDependentName(runConfigData.jsOutputFilePath)
|
||||
|
||||
val klass = when (declaration) {
|
||||
is KtClassOrObject -> declaration
|
||||
is KtNamedFunction -> declaration.containingClassOrObject ?: return null
|
||||
else -> return null
|
||||
return@getGenericTestIcon SmartList(location)
|
||||
}
|
||||
locations += klass.parentsWithSelf.filterIsInstance<KtNamedDeclaration>().mapNotNull { it.name }.toList().asReversed()
|
||||
|
||||
val testName = (declaration as? KtNamedFunction)?.name
|
||||
if (testName != null) {
|
||||
locations += "$testName"
|
||||
}
|
||||
|
||||
val prefix = if (testName != null) "test://" else "suite://"
|
||||
|
||||
val url = prefix + locations.joinWithEscape('.')
|
||||
|
||||
return getTestStateIcon(url, declaration.project)
|
||||
}
|
||||
|
||||
override fun acceptsAsEntryPoint(function: KtFunction): Boolean {
|
||||
@@ -114,17 +91,4 @@ class JsIdePlatformKindTooling : IdePlatformKindTooling() {
|
||||
ConfigurationContext.createEmptyContextForLocation(it)
|
||||
}.ifEmpty { listOf(ConfigurationContext.createEmptyContextForLocation(location)) }.asSequence()
|
||||
}
|
||||
|
||||
private fun DeclarationDescriptor.isIgnored(): Boolean =
|
||||
annotations.any { it.fqName == IGNORE_FQ_NAME } || ((containingDeclaration as? ClassDescriptor)?.isIgnored() ?: false)
|
||||
|
||||
private fun DeclarationDescriptor.isTest(): Boolean {
|
||||
if (isIgnored()) return false
|
||||
|
||||
if (annotations.any { it.fqName == TEST_FQ_NAME }) return true
|
||||
if (this is ClassDescriptorWithResolutionScopes) {
|
||||
return declaredCallableMembers.any { it.isTest() }
|
||||
}
|
||||
return false
|
||||
}
|
||||
}
|
||||
@@ -24,7 +24,6 @@ import org.jetbrains.kotlin.psi.KtClassOrObject
|
||||
import org.jetbrains.kotlin.psi.KtFunction
|
||||
import org.jetbrains.kotlin.psi.KtNamedDeclaration
|
||||
import org.jetbrains.kotlin.psi.KtNamedFunction
|
||||
import org.jetbrains.kotlin.resolve.jvm.JvmResolverForModuleFactory
|
||||
import org.jetbrains.kotlin.utils.PathUtil
|
||||
import javax.swing.Icon
|
||||
|
||||
@@ -73,7 +72,7 @@ class JvmIdePlatformKindTooling : IdePlatformKindTooling() {
|
||||
|
||||
else -> return null
|
||||
}
|
||||
return getTestStateIcon(url, declaration.project) ?: framework.icon
|
||||
return getTestStateIcon(url, declaration.project, strict = false) ?: framework.icon
|
||||
}
|
||||
|
||||
override fun acceptsAsEntryPoint(function: KtFunction) = true
|
||||
|
||||
@@ -0,0 +1,72 @@
|
||||
/*
|
||||
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* 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.platform
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.ClassDescriptorWithResolutionScopes
|
||||
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
||||
import org.jetbrains.kotlin.idea.highlighter.KotlinTestRunLineMarkerContributor.Companion.getTestStateIcon
|
||||
import org.jetbrains.kotlin.idea.util.string.joinWithEscape
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.psi.KtClassOrObject
|
||||
import org.jetbrains.kotlin.psi.KtNamedDeclaration
|
||||
import org.jetbrains.kotlin.psi.KtNamedFunction
|
||||
import org.jetbrains.kotlin.psi.psiUtil.containingClassOrObject
|
||||
import org.jetbrains.kotlin.psi.psiUtil.parentsWithSelf
|
||||
import javax.swing.Icon
|
||||
|
||||
private val TEST_FQ_NAME = FqName("kotlin.test.Test")
|
||||
private val IGNORE_FQ_NAME = FqName("kotlin.test.Ignore")
|
||||
|
||||
fun getGenericTestIcon(declaration: KtNamedDeclaration, descriptor: DeclarationDescriptor, initialLocations: () -> List<String>?): Icon? {
|
||||
if (!descriptor.isKotlinTestDeclaration()) return null
|
||||
|
||||
val locations = initialLocations()?.toMutableList() ?: return null
|
||||
|
||||
val clazz = when (declaration) {
|
||||
is KtClassOrObject -> declaration
|
||||
is KtNamedFunction -> declaration.containingClassOrObject ?: return null
|
||||
else -> return null
|
||||
}
|
||||
|
||||
locations += clazz.parentsWithSelf.filterIsInstance<KtNamedDeclaration>()
|
||||
.mapNotNull { it.name }
|
||||
.toList().asReversed()
|
||||
|
||||
val testName = (declaration as? KtNamedFunction)?.name
|
||||
if (testName != null) {
|
||||
locations += "$testName"
|
||||
}
|
||||
|
||||
val prefix = if (testName != null) "test://" else "suite://"
|
||||
val url = prefix + locations.joinWithEscape('.')
|
||||
val javaUrl = "java:$url"
|
||||
|
||||
val project = declaration.project
|
||||
return getTestStateIcon(javaUrl, project, strict = true) ?: getTestStateIcon(url, project, strict = false)
|
||||
}
|
||||
|
||||
private tailrec fun DeclarationDescriptor.isIgnored(): Boolean {
|
||||
if (annotations.any { it.fqName == IGNORE_FQ_NAME }) {
|
||||
return true
|
||||
}
|
||||
|
||||
val containingClass = containingDeclaration as? ClassDescriptor ?: return false
|
||||
return containingClass.isIgnored()
|
||||
}
|
||||
|
||||
fun DeclarationDescriptor.isKotlinTestDeclaration(): Boolean {
|
||||
if (isIgnored()) {
|
||||
return false
|
||||
}
|
||||
|
||||
if (annotations.any { it.fqName == TEST_FQ_NAME }) {
|
||||
return true
|
||||
}
|
||||
|
||||
val classDescriptor = this as? ClassDescriptorWithResolutionScopes ?: return false
|
||||
return classDescriptor.declaredCallableMembers.any { it.isKotlinTestDeclaration() }
|
||||
}
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
/*
|
||||
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* 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.ide.konan
|
||||
|
||||
interface KotlinNativeRunConfigurationProvider {
|
||||
val isForTests: Boolean
|
||||
}
|
||||
+17
-2
@@ -5,17 +5,18 @@
|
||||
|
||||
package org.jetbrains.kotlin.ide.konan
|
||||
|
||||
import com.intellij.execution.actions.RunConfigurationProducer
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.openapi.roots.libraries.DummyLibraryProperties
|
||||
import com.intellij.openapi.roots.libraries.Library
|
||||
import com.intellij.openapi.roots.libraries.PersistentLibraryKind
|
||||
import com.intellij.openapi.roots.ui.configuration.libraries.CustomLibraryDescription
|
||||
import org.jetbrains.kotlin.ide.konan.analyzer.NativeResolverForModuleFactory
|
||||
import org.jetbrains.kotlin.cli.common.arguments.CommonCompilerArguments
|
||||
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
||||
import org.jetbrains.kotlin.gradle.KotlinPlatform
|
||||
import org.jetbrains.kotlin.idea.framework.KotlinLibraryKind
|
||||
import org.jetbrains.kotlin.idea.platform.IdePlatformKindTooling
|
||||
import org.jetbrains.kotlin.idea.platform.getGenericTestIcon
|
||||
import org.jetbrains.kotlin.platform.impl.NativeIdePlatformKind
|
||||
import org.jetbrains.kotlin.psi.KtFunction
|
||||
import org.jetbrains.kotlin.psi.KtNamedDeclaration
|
||||
@@ -37,7 +38,21 @@ class NativeIdePlatformKindTooling : IdePlatformKindTooling() {
|
||||
override fun getLibraryDescription(project: Project): CustomLibraryDescription? = null
|
||||
override fun getLibraryVersionProvider(project: Project): (Library) -> String? = { null }
|
||||
|
||||
override fun getTestIcon(declaration: KtNamedDeclaration, descriptor: DeclarationDescriptor): Icon? = null
|
||||
override fun getTestIcon(declaration: KtNamedDeclaration, descriptor: DeclarationDescriptor): Icon? {
|
||||
return getGenericTestIcon(declaration, descriptor) {
|
||||
val availableRunConfigurations = RunConfigurationProducer
|
||||
.getProducers(declaration.project)
|
||||
.asSequence()
|
||||
.filterIsInstance<KotlinNativeRunConfigurationProvider>()
|
||||
.filter { it.isForTests }
|
||||
|
||||
if (availableRunConfigurations.firstOrNull() == null) {
|
||||
return@getGenericTestIcon null
|
||||
}
|
||||
|
||||
return@getGenericTestIcon emptyList()
|
||||
}
|
||||
}
|
||||
|
||||
override fun acceptsAsEntryPoint(function: KtFunction) = false
|
||||
}
|
||||
|
||||
+4
-2
@@ -38,9 +38,11 @@ import javax.swing.Icon
|
||||
|
||||
class KotlinTestRunLineMarkerContributor : RunLineMarkerContributor() {
|
||||
companion object {
|
||||
fun getTestStateIcon(url: String, project: Project): Icon? {
|
||||
fun getTestStateIcon(url: String, project: Project, strict: Boolean): Icon? {
|
||||
val defaultIcon = AllIcons.RunConfigurations.TestState.Run
|
||||
val state = TestStateStorage.getInstance(project).getState(url) ?: return defaultIcon
|
||||
val state = TestStateStorage.getInstance(project).getState(url)
|
||||
?: return if (strict) null else defaultIcon
|
||||
|
||||
return when (TestIconMapper.getMagnitude(state.magnitude)) {
|
||||
TestStateInfo.Magnitude.ERROR_INDEX,
|
||||
TestStateInfo.Magnitude.FAILED_INDEX -> AllIcons.RunConfigurations.TestState.Red2
|
||||
|
||||
Reference in New Issue
Block a user