diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/checkers/HeaderImplDeclarationChecker.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/checkers/HeaderImplDeclarationChecker.kt index 24325f630ac..c6fc3a2b28a 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/checkers/HeaderImplDeclarationChecker.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/checkers/HeaderImplDeclarationChecker.kt @@ -232,6 +232,13 @@ object HeaderImplDeclarationChecker : DeclarationChecker { fun MemberDescriptor.findCompatibleImplForHeader(platformModule: ModuleDescriptor): List = findImplForHeader(this, platformModule, false)?.get(Compatible).orEmpty() + fun MemberDescriptor.findAnyImplForHeader(platformModule: ModuleDescriptor): List { + val implsGroupedByCompatibility = findImplForHeader(this, platformModule, false) + return implsGroupedByCompatibility?.get(Compatible) + ?: implsGroupedByCompatibility?.values?.flatten() + ?: emptyList() + } + fun MemberDescriptor.findCompatibleHeaderForImpl(commonModule: ModuleDescriptor): List = findHeaderForImpl(this, commonModule)?.get(Compatible).orEmpty() diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/util/ProjectRootsUtil.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/util/ProjectRootsUtil.kt index 6de6e0af034..d2cde1c1e7e 100644 --- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/util/ProjectRootsUtil.kt +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/util/ProjectRootsUtil.kt @@ -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) diff --git a/idea/idea-jvm/src/org/jetbrains/kotlin/idea/run/KotlinMultiplatformJUnitRecognizer.kt b/idea/idea-jvm/src/org/jetbrains/kotlin/idea/run/KotlinMultiplatformJUnitRecognizer.kt new file mode 100644 index 00000000000..8f9b365c42c --- /dev/null +++ b/idea/idea-jvm/src/org/jetbrains/kotlin/idea/run/KotlinMultiplatformJUnitRecognizer.kt @@ -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): 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() + .any { it.classDescriptor?.fqNameSafe?.asString() == fqName } + } +} diff --git a/idea/src/META-INF/junit.xml b/idea/src/META-INF/junit.xml index 94aa5be13c8..bde8ad8285f 100644 --- a/idea/src/META-INF/junit.xml +++ b/idea/src/META-INF/junit.xml @@ -2,5 +2,6 @@ + diff --git a/idea/src/org/jetbrains/kotlin/idea/highlighter/markers/ImplementedHeaderMarker.kt b/idea/src/org/jetbrains/kotlin/idea/highlighter/markers/ImplementedHeaderMarker.kt index cb057626907..ff94f03bb29 100644 --- a/idea/src/org/jetbrains/kotlin/idea/highlighter/markers/ImplementedHeaderMarker.kt +++ b/idea/src/org/jetbrains/kotlin/idea/highlighter/markers/ImplementedHeaderMarker.kt @@ -34,9 +34,14 @@ import java.awt.event.MouseEvent fun ModuleDescriptor.hasImplementationsOf(descriptor: MemberDescriptor) = implementationsOf(descriptor).isNotEmpty() -private fun ModuleDescriptor.implementationsOf(descriptor: MemberDescriptor): List = +fun ModuleDescriptor.implementationsOf(descriptor: MemberDescriptor, checkCompatible: Boolean = true): List = with(HeaderImplDeclarationChecker) { - descriptor.findCompatibleImplForHeader(this@implementationsOf) + if (checkCompatible) { + descriptor.findCompatibleImplForHeader(this@implementationsOf) + } + else { + descriptor.findAnyImplForHeader(this@implementationsOf) + } } fun getPlatformImplementationTooltip(declaration: KtDeclaration): String? {