Consider only source-compatible modules in allImplementingModules use-sites
So #KT-17400 Fixed So #KT-15680 Fixed So #KT-15660 Fixed Likely also #KT-16838 Fixed
This commit is contained in:
committed by
Mikhail Glukhikh
parent
956ace3463
commit
0798e43524
+20
-1
@@ -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)
|
||||
|
||||
@@ -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? =
|
||||
|
||||
@@ -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<KtDeclaration> {
|
||||
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 }
|
||||
}
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
header class <error descr="[HEADER_WITHOUT_IMPLEMENTATION] Header declaration 'My' has no implementation in module jvm (test) for JVM"><error descr="[HEADER_WITHOUT_IMPLEMENTATION] Header declaration 'My' has no implementation in module jvm for JVM">My</error></error> {
|
||||
header class <error descr="[HEADER_WITHOUT_IMPLEMENTATION] Header declaration 'My' has no implementation in module jvm for JVM">My</error> {
|
||||
|
||||
}
|
||||
Vendored
+1
-1
@@ -1,3 +1,3 @@
|
||||
header class <error descr="[HEADER_WITHOUT_IMPLEMENTATION] Header declaration 'My' has no implementation in module js (test) for JS"><error descr="[HEADER_WITHOUT_IMPLEMENTATION] Header declaration 'My' has no implementation in module js for JS"><error descr="[HEADER_WITHOUT_IMPLEMENTATION] Header declaration 'My' has no implementation in module jvm (test) for JVM"><error descr="[HEADER_WITHOUT_IMPLEMENTATION] Header declaration 'My' has no implementation in module jvm for JVM">My</error></error></error></error> {
|
||||
header class <error descr="[HEADER_WITHOUT_IMPLEMENTATION] Header declaration 'My' has no implementation in module js for JS"><error descr="[HEADER_WITHOUT_IMPLEMENTATION] Header declaration 'My' has no implementation in module jvm for JVM">My</error></error> {
|
||||
|
||||
}
|
||||
Vendored
+1
-1
@@ -4,4 +4,4 @@
|
||||
header interface Event
|
||||
|
||||
@Suppress("SOMETHING_WRONG")
|
||||
header class <error descr="[HEADER_WITHOUT_IMPLEMENTATION] Header declaration 'Wrong' has no implementation in module jvm (test) for JVM"><error descr="[HEADER_WITHOUT_IMPLEMENTATION] Header declaration 'Wrong' has no implementation in module jvm for JVM">Wrong</error></error>
|
||||
header class <error descr="[HEADER_WITHOUT_IMPLEMENTATION] Header declaration 'Wrong' has no implementation in module jvm for JVM">Wrong</error>
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
header fun foo(arg: Int): Int
|
||||
|
||||
<error>header fun foo(): Int</error>
|
||||
@@ -0,0 +1 @@
|
||||
impl fun foo(arg: Int) = arg
|
||||
@@ -0,0 +1,3 @@
|
||||
header fun <lineMarker descr="Has implementations in JVM">foo</lineMarker>(): Int
|
||||
|
||||
header fun <lineMarker descr="Has implementations in JVM">foo</lineMarker>(arg: Int): Int
|
||||
@@ -0,0 +1,5 @@
|
||||
// !CHECK_HIGHLIGHTING
|
||||
|
||||
impl fun foo() = 42
|
||||
|
||||
impl fun foo(arg: Int) = 7 * arg
|
||||
@@ -0,0 +1,5 @@
|
||||
// "Create header function implementation for platform JVM" "true"
|
||||
|
||||
package test
|
||||
|
||||
header fun <caret>testHelper()
|
||||
@@ -0,0 +1,5 @@
|
||||
// "Create header function implementation for platform JVM" "true"
|
||||
|
||||
package test
|
||||
|
||||
header fun testHelper()
|
||||
@@ -0,0 +1 @@
|
||||
// testHelper: NOT to be implemented
|
||||
@@ -0,0 +1 @@
|
||||
// testHelper: NOT to be implemented
|
||||
@@ -0,0 +1,3 @@
|
||||
// testHelper: to be implemented
|
||||
|
||||
package test
|
||||
@@ -0,0 +1,5 @@
|
||||
// testHelper: to be implemented
|
||||
|
||||
package test
|
||||
|
||||
impl fun testHelper() {}
|
||||
@@ -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 ->
|
||||
|
||||
@@ -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])
|
||||
}
|
||||
}
|
||||
@@ -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(" ") ?: "<root>"
|
||||
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)
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user