diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/highlighter/PlatformHeaderAnnotator.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/highlighter/PlatformHeaderAnnotator.kt index ee293bdaae0..a99b5fb6fc1 100644 --- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/highlighter/PlatformHeaderAnnotator.kt +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/highlighter/PlatformHeaderAnnotator.kt @@ -19,11 +19,14 @@ package org.jetbrains.kotlin.idea.highlighter import com.intellij.lang.annotation.AnnotationHolder import com.intellij.lang.annotation.Annotator import com.intellij.psi.PsiElement +import org.jetbrains.kotlin.analyzer.ModuleInfo import org.jetbrains.kotlin.caches.resolve.KotlinCacheService import org.jetbrains.kotlin.descriptors.MemberDescriptor import org.jetbrains.kotlin.descriptors.ModuleDescriptor import org.jetbrains.kotlin.diagnostics.Diagnostic import org.jetbrains.kotlin.diagnostics.DiagnosticSink +import org.jetbrains.kotlin.idea.caches.resolve.ModuleProductionSourceInfo +import org.jetbrains.kotlin.idea.caches.resolve.ModuleTestSourceInfo import org.jetbrains.kotlin.idea.caches.resolve.findModuleDescriptor import org.jetbrains.kotlin.idea.core.toDescriptor import org.jetbrains.kotlin.idea.project.TargetPlatformDetector @@ -34,6 +37,22 @@ import org.jetbrains.kotlin.resolve.checkers.HeaderImplDeclarationChecker import org.jetbrains.kotlin.resolve.diagnostics.Diagnostics import org.jetbrains.kotlin.resolve.diagnostics.SimpleDiagnostics +val ModuleDescriptor.sourceKind: SourceKind + get() = when (getCapability(ModuleInfo.Capability)) { + is ModuleProductionSourceInfo -> SourceKind.PRODUCTION + is ModuleTestSourceInfo -> SourceKind.TEST + else -> SourceKind.OTHER + } + +enum class SourceKind { OTHER, PRODUCTION, TEST } + +val ModuleDescriptor.allImplementingCompatibleModules + get() = allImplementingModules.filter { + sourceKind == SourceKind.OTHER || + it.sourceKind == SourceKind.OTHER || + it.sourceKind == sourceKind + } + class PlatformHeaderAnnotator : Annotator { override fun annotate(element: PsiElement, holder: AnnotationHolder) { @@ -43,7 +62,7 @@ class PlatformHeaderAnnotator : Annotator { if (TargetPlatformDetector.getPlatform(declaration.containingKtFile) !is TargetPlatform.Default) return val defaultModuleDescriptor = declaration.findModuleDescriptor() - val dependentDescriptors = defaultModuleDescriptor.allImplementingModules + val dependentDescriptors = defaultModuleDescriptor.allImplementingCompatibleModules if (dependentDescriptors.isEmpty()) return val diagnostics = validate(declaration, dependentDescriptors) diff --git a/idea/src/org/jetbrains/kotlin/idea/highlighter/markers/DeclaredHeaderMarker.kt b/idea/src/org/jetbrains/kotlin/idea/highlighter/markers/DeclaredHeaderMarker.kt index 17d2411d0ea..ffacfe1f7c4 100644 --- a/idea/src/org/jetbrains/kotlin/idea/highlighter/markers/DeclaredHeaderMarker.kt +++ b/idea/src/org/jetbrains/kotlin/idea/highlighter/markers/DeclaredHeaderMarker.kt @@ -16,14 +16,10 @@ package org.jetbrains.kotlin.idea.highlighter.markers -import org.jetbrains.kotlin.analyzer.ModuleInfo -import org.jetbrains.kotlin.descriptors.DeclarationDescriptor -import org.jetbrains.kotlin.descriptors.MemberDescriptor -import org.jetbrains.kotlin.descriptors.ModuleDescriptor -import org.jetbrains.kotlin.idea.caches.resolve.ModuleProductionSourceInfo -import org.jetbrains.kotlin.idea.caches.resolve.ModuleTestSourceInfo +import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.idea.caches.resolve.findModuleDescriptor import org.jetbrains.kotlin.idea.core.toDescriptor +import org.jetbrains.kotlin.idea.highlighter.sourceKind import org.jetbrains.kotlin.lexer.KtTokens import org.jetbrains.kotlin.psi.KtDeclaration import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils @@ -39,15 +35,6 @@ fun ModuleDescriptor.commonModuleOrNull(): ModuleDescriptor? { } } -private val ModuleDescriptor.sourceKind: SourceKind - get() = when (getCapability(ModuleInfo.Capability)) { - is ModuleProductionSourceInfo -> SourceKind.PRODUCTION - is ModuleTestSourceInfo -> SourceKind.TEST - else -> SourceKind.NONE - } - -private enum class SourceKind { NONE, PRODUCTION, TEST } - fun ModuleDescriptor.hasDeclarationOf(descriptor: MemberDescriptor) = declarationOf(descriptor) != null private fun ModuleDescriptor.declarationOf(descriptor: MemberDescriptor): DeclarationDescriptor? = 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 1f8e5d1f421..d7754158fde 100644 --- a/idea/src/org/jetbrains/kotlin/idea/highlighter/markers/ImplementedHeaderMarker.kt +++ b/idea/src/org/jetbrains/kotlin/idea/highlighter/markers/ImplementedHeaderMarker.kt @@ -23,6 +23,7 @@ import org.jetbrains.kotlin.descriptors.MemberDescriptor import org.jetbrains.kotlin.descriptors.ModuleDescriptor import org.jetbrains.kotlin.idea.caches.resolve.findModuleDescriptor import org.jetbrains.kotlin.idea.core.toDescriptor +import org.jetbrains.kotlin.idea.highlighter.allImplementingCompatibleModules import org.jetbrains.kotlin.psi.KtDeclaration import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils import org.jetbrains.kotlin.resolve.MultiTargetPlatform @@ -42,7 +43,7 @@ fun getPlatformImplementationTooltip(declaration: KtDeclaration): String? { val descriptor = declaration.toDescriptor() as? MemberDescriptor ?: return null val commonModuleDescriptor = declaration.containingKtFile.findModuleDescriptor() - val platformModulesWithImplementation = commonModuleDescriptor.allImplementingModules.filter { + val platformModulesWithImplementation = commonModuleDescriptor.allImplementingCompatibleModules.filter { it.hasImplementationsOf(descriptor) } if (platformModulesWithImplementation.isEmpty()) return null @@ -67,7 +68,7 @@ fun navigateToPlatformImplementation(e: MouseEvent?, declaration: KtDeclaration) internal fun KtDeclaration.headerImplementations(): Set { val descriptor = toDescriptor() as? MemberDescriptor ?: return emptySet() val commonModuleDescriptor = containingKtFile.findModuleDescriptor() - return commonModuleDescriptor.allImplementingModules.flatMap { + return commonModuleDescriptor.allImplementingCompatibleModules.flatMap { it.implementationsOf(descriptor) }.mapNotNullTo(LinkedHashSet()) { DescriptorToSourceUtils.descriptorToDeclaration(it) as? KtDeclaration } } \ No newline at end of file diff --git a/idea/src/org/jetbrains/kotlin/idea/highlighter/markers/KotlinLineMarkerProvider.kt b/idea/src/org/jetbrains/kotlin/idea/highlighter/markers/KotlinLineMarkerProvider.kt index dd30cd763cf..509b3d5c6f7 100644 --- a/idea/src/org/jetbrains/kotlin/idea/highlighter/markers/KotlinLineMarkerProvider.kt +++ b/idea/src/org/jetbrains/kotlin/idea/highlighter/markers/KotlinLineMarkerProvider.kt @@ -41,6 +41,7 @@ import org.jetbrains.kotlin.descriptors.Modality import org.jetbrains.kotlin.idea.KotlinIcons import org.jetbrains.kotlin.idea.caches.resolve.findModuleDescriptor import org.jetbrains.kotlin.idea.core.toDescriptor +import org.jetbrains.kotlin.idea.highlighter.allImplementingCompatibleModules import org.jetbrains.kotlin.idea.util.ProjectRootsUtil import org.jetbrains.kotlin.lexer.KtTokens import org.jetbrains.kotlin.psi.* @@ -286,7 +287,7 @@ private fun collectImplementationMarkers(declaration: KtNamedDeclaration, val descriptor = declaration.toDescriptor() as? MemberDescriptor ?: return val commonModuleDescriptor = declaration.containingKtFile.findModuleDescriptor() - if (commonModuleDescriptor.allImplementingModules.none { it.hasImplementationsOf(descriptor) }) return + if (commonModuleDescriptor.allImplementingCompatibleModules.none { it.hasImplementationsOf(descriptor) }) return val anchor = declaration.nameIdentifier ?: declaration diff --git a/idea/src/org/jetbrains/kotlin/idea/inspections/UnusedSymbolInspection.kt b/idea/src/org/jetbrains/kotlin/idea/inspections/UnusedSymbolInspection.kt index 866dc485d0a..c66b0ee27c4 100644 --- a/idea/src/org/jetbrains/kotlin/idea/inspections/UnusedSymbolInspection.kt +++ b/idea/src/org/jetbrains/kotlin/idea/inspections/UnusedSymbolInspection.kt @@ -55,6 +55,7 @@ import org.jetbrains.kotlin.idea.caches.resolve.resolveToDescriptorIfAny import org.jetbrains.kotlin.idea.core.toDescriptor import org.jetbrains.kotlin.idea.findUsages.KotlinFindUsagesHandlerFactory import org.jetbrains.kotlin.idea.findUsages.handlers.KotlinFindClassUsagesHandler +import org.jetbrains.kotlin.idea.highlighter.allImplementingCompatibleModules import org.jetbrains.kotlin.idea.highlighter.markers.hasImplementationsOf import org.jetbrains.kotlin.idea.imports.importableFqName import org.jetbrains.kotlin.idea.references.mainReference @@ -335,7 +336,7 @@ class UnusedSymbolInspection : AbstractKotlinInspection() { descriptor as? MemberDescriptor ?: return false val commonModuleDescriptor = declaration.containingKtFile.findModuleDescriptor() - return commonModuleDescriptor.allImplementingModules.any { it.hasImplementationsOf(descriptor) } || + return commonModuleDescriptor.allImplementingCompatibleModules.any { it.hasImplementationsOf(descriptor) } || commonModuleDescriptor.hasImplementationsOf(descriptor) } diff --git a/idea/testData/multiModuleHighlighting/multiplatform/basic/common/common.kt b/idea/testData/multiModuleHighlighting/multiplatform/basic/common/common.kt index 1064764e0fa..64e7831f3eb 100644 --- a/idea/testData/multiModuleHighlighting/multiplatform/basic/common/common.kt +++ b/idea/testData/multiModuleHighlighting/multiplatform/basic/common/common.kt @@ -1,3 +1,3 @@ -header class My { +header class My { } \ No newline at end of file diff --git a/idea/testData/multiModuleHighlighting/multiplatform/headerWithoutImplForBoth/common/common.kt b/idea/testData/multiModuleHighlighting/multiplatform/headerWithoutImplForBoth/common/common.kt index d2aa5ef3448..179a0da5e7e 100644 --- a/idea/testData/multiModuleHighlighting/multiplatform/headerWithoutImplForBoth/common/common.kt +++ b/idea/testData/multiModuleHighlighting/multiplatform/headerWithoutImplForBoth/common/common.kt @@ -1,3 +1,3 @@ -header class My { +header class My { } \ No newline at end of file diff --git a/idea/testData/multiModuleHighlighting/multiplatform/suppressHeaderWithoutImpl/common/common.kt b/idea/testData/multiModuleHighlighting/multiplatform/suppressHeaderWithoutImpl/common/common.kt index 8ead429a4f8..2aa4fa9af7b 100644 --- a/idea/testData/multiModuleHighlighting/multiplatform/suppressHeaderWithoutImpl/common/common.kt +++ b/idea/testData/multiModuleHighlighting/multiplatform/suppressHeaderWithoutImpl/common/common.kt @@ -4,4 +4,4 @@ header interface Event @Suppress("SOMETHING_WRONG") -header class Wrong \ No newline at end of file +header class Wrong \ No newline at end of file diff --git a/idea/testData/multiModuleHighlighting/multiplatform/withOverrides/common/common.kt b/idea/testData/multiModuleHighlighting/multiplatform/withOverrides/common/common.kt new file mode 100644 index 00000000000..9f0391e725b --- /dev/null +++ b/idea/testData/multiModuleHighlighting/multiplatform/withOverrides/common/common.kt @@ -0,0 +1,3 @@ +header fun foo(arg: Int): Int + +header fun foo(): Int diff --git a/idea/testData/multiModuleHighlighting/multiplatform/withOverrides/jvm/jvm.kt b/idea/testData/multiModuleHighlighting/multiplatform/withOverrides/jvm/jvm.kt new file mode 100644 index 00000000000..1922060a08b --- /dev/null +++ b/idea/testData/multiModuleHighlighting/multiplatform/withOverrides/jvm/jvm.kt @@ -0,0 +1 @@ +impl fun foo(arg: Int) = arg \ No newline at end of file diff --git a/idea/testData/multiModuleLineMarker/withOverloads/common/common.kt b/idea/testData/multiModuleLineMarker/withOverloads/common/common.kt new file mode 100644 index 00000000000..65362eed3e2 --- /dev/null +++ b/idea/testData/multiModuleLineMarker/withOverloads/common/common.kt @@ -0,0 +1,3 @@ +header fun foo(): Int + +header fun foo(arg: Int): Int diff --git a/idea/testData/multiModuleLineMarker/withOverloads/jvm/jvm.kt b/idea/testData/multiModuleLineMarker/withOverloads/jvm/jvm.kt new file mode 100644 index 00000000000..176b1050ceb --- /dev/null +++ b/idea/testData/multiModuleLineMarker/withOverloads/jvm/jvm.kt @@ -0,0 +1,5 @@ +// !CHECK_HIGHLIGHTING + +impl fun foo() = 42 + +impl fun foo(arg: Int) = 7 * arg \ No newline at end of file diff --git a/idea/testData/multiModuleQuickFix/withTest/common/common.kt b/idea/testData/multiModuleQuickFix/withTest/common/common.kt new file mode 100644 index 00000000000..e69de29bb2d diff --git a/idea/testData/multiModuleQuickFix/withTest/common/common.kt.after b/idea/testData/multiModuleQuickFix/withTest/common/common.kt.after new file mode 100644 index 00000000000..e69de29bb2d diff --git a/idea/testData/multiModuleQuickFix/withTest/commonTest/test/test.kt b/idea/testData/multiModuleQuickFix/withTest/commonTest/test/test.kt new file mode 100644 index 00000000000..1d8944cbb3e --- /dev/null +++ b/idea/testData/multiModuleQuickFix/withTest/commonTest/test/test.kt @@ -0,0 +1,5 @@ +// "Create header function implementation for platform JVM" "true" + +package test + +header fun testHelper() \ No newline at end of file diff --git a/idea/testData/multiModuleQuickFix/withTest/commonTest/test/test.kt.after b/idea/testData/multiModuleQuickFix/withTest/commonTest/test/test.kt.after new file mode 100644 index 00000000000..e4b08edf563 --- /dev/null +++ b/idea/testData/multiModuleQuickFix/withTest/commonTest/test/test.kt.after @@ -0,0 +1,5 @@ +// "Create header function implementation for platform JVM" "true" + +package test + +header fun testHelper() \ No newline at end of file diff --git a/idea/testData/multiModuleQuickFix/withTest/jvm/testHelper.kt b/idea/testData/multiModuleQuickFix/withTest/jvm/testHelper.kt new file mode 100644 index 00000000000..c87c974368b --- /dev/null +++ b/idea/testData/multiModuleQuickFix/withTest/jvm/testHelper.kt @@ -0,0 +1 @@ +// testHelper: NOT to be implemented \ No newline at end of file diff --git a/idea/testData/multiModuleQuickFix/withTest/jvm/testHelper.kt.after b/idea/testData/multiModuleQuickFix/withTest/jvm/testHelper.kt.after new file mode 100644 index 00000000000..c87c974368b --- /dev/null +++ b/idea/testData/multiModuleQuickFix/withTest/jvm/testHelper.kt.after @@ -0,0 +1 @@ +// testHelper: NOT to be implemented \ No newline at end of file diff --git a/idea/testData/multiModuleQuickFix/withTest/jvmTest/test/testHelper.kt b/idea/testData/multiModuleQuickFix/withTest/jvmTest/test/testHelper.kt new file mode 100644 index 00000000000..2b774b34d6a --- /dev/null +++ b/idea/testData/multiModuleQuickFix/withTest/jvmTest/test/testHelper.kt @@ -0,0 +1,3 @@ +// testHelper: to be implemented + +package test \ No newline at end of file diff --git a/idea/testData/multiModuleQuickFix/withTest/jvmTest/test/testHelper.kt.after b/idea/testData/multiModuleQuickFix/withTest/jvmTest/test/testHelper.kt.after new file mode 100644 index 00000000000..4bbabd3b4b6 --- /dev/null +++ b/idea/testData/multiModuleQuickFix/withTest/jvmTest/test/testHelper.kt.after @@ -0,0 +1,5 @@ +// testHelper: to be implemented + +package test + +impl fun testHelper() {} \ No newline at end of file diff --git a/idea/tests/org/jetbrains/kotlin/idea/caches/resolve/MultiModuleHighlightingTest.kt b/idea/tests/org/jetbrains/kotlin/idea/caches/resolve/MultiModuleHighlightingTest.kt index 282fab71b7d..ee497a7af8d 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/caches/resolve/MultiModuleHighlightingTest.kt +++ b/idea/tests/org/jetbrains/kotlin/idea/caches/resolve/MultiModuleHighlightingTest.kt @@ -93,6 +93,10 @@ class MultiModuleHighlightingTest : AbstractMultiModuleHighlightingTest() { doMultiPlatformTest(TargetPlatformKind.Jvm[JvmTarget.JVM_1_6], withStdlibCommon = true) } + fun testWithOverrides() { + doMultiPlatformTest(TargetPlatformKind.Jvm[JvmTarget.JVM_1_6]) + } + fun testUseCorrectBuiltInsForCommonModule() { doMultiPlatformTest(TargetPlatformKind.Jvm[JvmTarget.JVM_1_8], TargetPlatformKind.JavaScript, withStdlibCommon = true, useFullJdk = true, configureModule = { module, platform -> diff --git a/idea/tests/org/jetbrains/kotlin/idea/caches/resolve/MultiModuleLineMarkerTest.kt b/idea/tests/org/jetbrains/kotlin/idea/caches/resolve/MultiModuleLineMarkerTest.kt index 9468f1addc3..4ec52fc797d 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/caches/resolve/MultiModuleLineMarkerTest.kt +++ b/idea/tests/org/jetbrains/kotlin/idea/caches/resolve/MultiModuleLineMarkerTest.kt @@ -32,4 +32,8 @@ class MultiModuleLineMarkerTest : AbstractMultiModuleLineMarkerTest() { fun testFromClassToAlias() { doMultiPlatformTest(TargetPlatformKind.Jvm[JvmTarget.JVM_1_6]) } + + fun testWithOverloads() { + doMultiPlatformTest(TargetPlatformKind.Jvm[JvmTarget.JVM_1_6]) + } } \ No newline at end of file diff --git a/idea/tests/org/jetbrains/kotlin/idea/quickfix/AbstractQuickFixMultiModuleTest.kt b/idea/tests/org/jetbrains/kotlin/idea/quickfix/AbstractQuickFixMultiModuleTest.kt index ec6b357a981..5bafa170211 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/quickfix/AbstractQuickFixMultiModuleTest.kt +++ b/idea/tests/org/jetbrains/kotlin/idea/quickfix/AbstractQuickFixMultiModuleTest.kt @@ -27,7 +27,6 @@ import junit.framework.ComparisonFailure import junit.framework.TestCase import org.jetbrains.kotlin.idea.inspections.findExistingEditor import org.jetbrains.kotlin.idea.project.PluginJetFilesProvider -import org.jetbrains.kotlin.idea.refactoring.createKotlinFile import org.jetbrains.kotlin.idea.stubs.AbstractMultiModuleTest import org.jetbrains.kotlin.idea.test.DirectiveBasedActionUtils import org.jetbrains.kotlin.idea.test.PluginTestCaseBase @@ -78,13 +77,13 @@ abstract class AbstractQuickFixMultiModuleTest : AbstractMultiModuleTest() { val testDirectory = File(testPath) val projectDirectory = File("$testPath${getTestName(true)}") for (moduleDirectory in projectDirectory.listFiles()) { - for (file in moduleDirectory.listFiles()) { + for (file in moduleDirectory.walkTopDown()) { if (!file.path.endsWith(".after")) continue try { - val editedFile = allFilesInProject.find { - it.name.toLowerCase() == file.name.removeSuffix(".after").toLowerCase() - } ?: allFilesInProject.mapNotNull { - it.containingDirectory?.findFile(file.name.removeSuffix(".after")) + val packageName = file.readLines().find { it.startsWith("package") }?.substringAfter(" ") ?: "" + val editedFile = allFilesInProject.mapNotNull { + val candidate = it.containingDirectory?.findFile(file.name.removeSuffix(".after")) as? KtFile + if (candidate?.packageFqName?.toString() == packageName) candidate else null }.single() setActiveEditor(editedFile.findExistingEditor() ?: createEditor(editedFile.virtualFile)) checkResultByFile(file.relativeTo(testDirectory).path) diff --git a/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixMultiModuleTest.kt b/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixMultiModuleTest.kt index 233dd98725f..3815bf138a9 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixMultiModuleTest.kt +++ b/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixMultiModuleTest.kt @@ -24,11 +24,12 @@ class QuickFixMultiModuleTest : AbstractQuickFixMultiModuleTest() { private fun doMultiPlatformTest(headerName: String = "header", implName: String = "jvm", - implKind: TargetPlatformKind<*> = TargetPlatformKind.Jvm[JvmTarget.JVM_1_6]) { - val header = module(headerName) + implKind: TargetPlatformKind<*> = TargetPlatformKind.Jvm[JvmTarget.JVM_1_6], + withTests: Boolean = false) { + val header = module(headerName, hasTestRoot = withTests) header.createFacet(TargetPlatformKind.Common) - val jvm = module(implName) + val jvm = module(implName, hasTestRoot = withTests) jvm.createFacet(implKind) jvm.enableMultiPlatform() jvm.addDependency(header) @@ -95,4 +96,9 @@ class QuickFixMultiModuleTest : AbstractQuickFixMultiModuleTest() { fun testSealed() { doMultiPlatformTest(implName = "js", implKind = TargetPlatformKind.JavaScript) } + + @Test + fun testWithTest() { + doMultiPlatformTest(headerName = "common", withTests = true) + } } \ No newline at end of file