Recognize common tests marked with annotations typealiased to @Test

This commit is contained in:
Dmitry Jemerov
2017-09-07 18:26:53 +02:00
parent 6d30123c21
commit 1d05e83401
5 changed files with 83 additions and 2 deletions
@@ -232,6 +232,13 @@ object HeaderImplDeclarationChecker : DeclarationChecker {
fun MemberDescriptor.findCompatibleImplForHeader(platformModule: ModuleDescriptor): List<MemberDescriptor> =
findImplForHeader(this, platformModule, false)?.get(Compatible).orEmpty()
fun MemberDescriptor.findAnyImplForHeader(platformModule: ModuleDescriptor): List<MemberDescriptor> {
val implsGroupedByCompatibility = findImplForHeader(this, platformModule, false)
return implsGroupedByCompatibility?.get(Compatible)
?: implsGroupedByCompatibility?.values?.flatten()
?: emptyList()
}
fun MemberDescriptor.findCompatibleHeaderForImpl(commonModule: ModuleDescriptor): List<MemberDescriptor> =
findHeaderForImpl(this, commonModule)?.get(Compatible).orEmpty()
@@ -20,6 +20,7 @@ import com.intellij.ide.highlighter.ArchiveFileType
import com.intellij.ide.highlighter.JavaClassFileType
import com.intellij.injected.editor.VirtualFileWindow
import com.intellij.openapi.module.Module
import com.intellij.openapi.module.ModuleUtilCore
import com.intellij.openapi.project.Project
import com.intellij.openapi.roots.FileIndex
import com.intellij.openapi.roots.ModuleRootManager
@@ -140,3 +141,6 @@ object ProjectRootsUtil {
val Module.rootManager: ModuleRootManager
get() = ModuleRootManager.getInstance(this)
val PsiElement.module: Module?
get() = ModuleUtilCore.findModuleForPsiElement(this)
@@ -0,0 +1,64 @@
/*
* Copyright 2010-2017 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.JUnitRecognizer
import com.intellij.psi.PsiMethod
import org.jetbrains.kotlin.asJava.elements.KtLightMethod
import org.jetbrains.kotlin.config.TargetPlatformKind
import org.jetbrains.kotlin.descriptors.ClassifierDescriptorWithTypeParameters
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
import org.jetbrains.kotlin.descriptors.TypeAliasDescriptor
import org.jetbrains.kotlin.descriptors.annotations.AnnotationWithTarget
import org.jetbrains.kotlin.idea.caches.resolve.analyze
import org.jetbrains.kotlin.idea.caches.resolve.findModuleDescriptor
import org.jetbrains.kotlin.idea.highlighter.allImplementingCompatibleModules
import org.jetbrains.kotlin.idea.highlighter.markers.implementationsOf
import org.jetbrains.kotlin.idea.project.targetPlatform
import org.jetbrains.kotlin.idea.util.module
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
class KotlinMultiplatformJUnitRecognizer : JUnitRecognizer() {
override fun isTestAnnotated(method: PsiMethod): Boolean {
if (method !is KtLightMethod) return false
val origin = method.kotlinOrigin ?: return false
if (origin.module?.targetPlatform !is TargetPlatformKind.Common) return false
val moduleDescriptor = origin.containingKtFile.findModuleDescriptor()
val implModules = moduleDescriptor.allImplementingCompatibleModules
if (implModules.isEmpty()) return false
val bindingContext = origin.analyze(BodyResolveMode.PARTIAL)
val methodDescriptor = bindingContext[BindingContext.DECLARATION_TO_DESCRIPTOR, origin] ?: return false
return methodDescriptor.annotations.getAllAnnotations().any { it.isHeaderOfAnnotation("org.junit.Test", implModules) }
}
}
private fun AnnotationWithTarget.isHeaderOfAnnotation(fqName: String, implModules: Collection<ModuleDescriptor>): Boolean {
val annotationClass = annotation.type.constructor.declarationDescriptor as? ClassifierDescriptorWithTypeParameters ?: return false
if (!annotationClass.isHeader) return false
return implModules
.any { module ->
module.implementationsOf(annotationClass, checkCompatible = false)
.filterIsInstance<TypeAliasDescriptor>()
.any { it.classDescriptor?.fqNameSafe?.asString() == fqName }
}
}
+1
View File
@@ -2,5 +2,6 @@
<extensions defaultExtensionNs="com.intellij">
<runConfigurationProducer implementation="org.jetbrains.kotlin.idea.run.KotlinJUnitRunConfigurationProducer"/>
<runConfigurationProducer implementation="org.jetbrains.kotlin.idea.run.KotlinPatternConfigurationProducer"/>
<junitRecognizer implementation="org.jetbrains.kotlin.idea.run.KotlinMultiplatformJUnitRecognizer"/>
</extensions>
</idea-plugin>
@@ -34,9 +34,14 @@ import java.awt.event.MouseEvent
fun ModuleDescriptor.hasImplementationsOf(descriptor: MemberDescriptor) =
implementationsOf(descriptor).isNotEmpty()
private fun ModuleDescriptor.implementationsOf(descriptor: MemberDescriptor): List<DeclarationDescriptor> =
fun ModuleDescriptor.implementationsOf(descriptor: MemberDescriptor, checkCompatible: Boolean = true): List<DeclarationDescriptor> =
with(HeaderImplDeclarationChecker) {
descriptor.findCompatibleImplForHeader(this@implementationsOf)
if (checkCompatible) {
descriptor.findCompatibleImplForHeader(this@implementationsOf)
}
else {
descriptor.findAnyImplForHeader(this@implementationsOf)
}
}
fun getPlatformImplementationTooltip(declaration: KtDeclaration): String? {