Create actual fix: use target module instead of target platform

This commit is contained in:
Mikhail Glukhikh
2018-03-05 18:02:07 +03:00
parent 90e4413fc9
commit ef3e0b01c4
40 changed files with 60 additions and 61 deletions
@@ -18,11 +18,13 @@ package org.jetbrains.kotlin.idea.highlighter.markers
import com.intellij.codeInsight.daemon.impl.PsiElementListNavigator import com.intellij.codeInsight.daemon.impl.PsiElementListNavigator
import com.intellij.ide.util.DefaultPsiElementCellRenderer import com.intellij.ide.util.DefaultPsiElementCellRenderer
import com.intellij.openapi.module.Module
import com.intellij.psi.PsiElement import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.analyzer.ModuleInfo
import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.idea.caches.project.ModuleSourceInfo
import org.jetbrains.kotlin.idea.caches.resolve.findModuleDescriptor import org.jetbrains.kotlin.idea.caches.resolve.findModuleDescriptor
import org.jetbrains.kotlin.idea.caches.resolve.resolveToDescriptorIfAny import org.jetbrains.kotlin.idea.caches.resolve.resolveToDescriptorIfAny
import org.jetbrains.kotlin.idea.caches.resolve.unsafeResolveToDescriptor
import org.jetbrains.kotlin.idea.core.toDescriptor import org.jetbrains.kotlin.idea.core.toDescriptor
import org.jetbrains.kotlin.idea.facet.implementingDescriptors import org.jetbrains.kotlin.idea.facet.implementingDescriptors
import org.jetbrains.kotlin.psi.KtDeclaration import org.jetbrains.kotlin.psi.KtDeclaration
@@ -90,10 +92,10 @@ private fun DeclarationDescriptor.actualsForExpected(): Collection<DeclarationDe
} }
// null means "any platform" here // null means "any platform" here
internal fun KtDeclaration.actualsForExpected(platform: MultiTargetPlatform? = null): Set<KtDeclaration> = internal fun KtDeclaration.actualsForExpected(module: Module? = null): Set<KtDeclaration> =
resolveToDescriptorIfAny(BodyResolveMode.FULL) resolveToDescriptorIfAny(BodyResolveMode.FULL)
?.actualsForExpected() ?.actualsForExpected()
?.filter { platform == null || it.module.getMultiTargetPlatform() == platform } ?.filter { module == null || (it.module.getCapability(ModuleInfo.Capability) as? ModuleSourceInfo)?.module == module }
?.mapNotNullTo(LinkedHashSet()) { ?.mapNotNullTo(LinkedHashSet()) {
DescriptorToSourceUtils.descriptorToDeclaration(it) as? KtDeclaration DescriptorToSourceUtils.descriptorToDeclaration(it) as? KtDeclaration
} ?: emptySet() } ?: emptySet()
@@ -21,19 +21,18 @@ import com.intellij.ide.util.EditorHelper
import com.intellij.ide.util.PackageUtil import com.intellij.ide.util.PackageUtil
import com.intellij.openapi.editor.Editor import com.intellij.openapi.editor.Editor
import com.intellij.openapi.module.Module import com.intellij.openapi.module.Module
import com.intellij.openapi.module.ModuleUtilCore
import com.intellij.openapi.project.Project import com.intellij.openapi.project.Project
import com.intellij.psi.JavaDirectoryService import com.intellij.psi.JavaDirectoryService
import com.intellij.psi.codeStyle.CodeStyleManager import com.intellij.psi.codeStyle.CodeStyleManager
import org.jetbrains.kotlin.analyzer.ModuleInfo
import org.jetbrains.kotlin.builtins.KotlinBuiltIns import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.diagnostics.Diagnostic import org.jetbrains.kotlin.diagnostics.Diagnostic
import org.jetbrains.kotlin.diagnostics.DiagnosticFactory import org.jetbrains.kotlin.diagnostics.DiagnosticFactory
import org.jetbrains.kotlin.diagnostics.Errors import org.jetbrains.kotlin.diagnostics.Errors
import org.jetbrains.kotlin.idea.caches.project.ModuleSourceInfo
import org.jetbrains.kotlin.idea.core.* import org.jetbrains.kotlin.idea.core.*
import org.jetbrains.kotlin.idea.facet.implementingModules
import org.jetbrains.kotlin.idea.highlighter.markers.actualsForExpected import org.jetbrains.kotlin.idea.highlighter.markers.actualsForExpected
import org.jetbrains.kotlin.idea.project.TargetPlatformDetector
import org.jetbrains.kotlin.idea.quickfix.KotlinQuickFixAction import org.jetbrains.kotlin.idea.quickfix.KotlinQuickFixAction
import org.jetbrains.kotlin.idea.quickfix.KotlinSingleIntentionActionFactory import org.jetbrains.kotlin.idea.quickfix.KotlinSingleIntentionActionFactory
import org.jetbrains.kotlin.idea.refactoring.createKotlinFile import org.jetbrains.kotlin.idea.refactoring.createKotlinFile
@@ -47,6 +46,7 @@ import org.jetbrains.kotlin.resolve.getMultiTargetPlatform
sealed class CreateActualFix<out D : KtNamedDeclaration>( sealed class CreateActualFix<out D : KtNamedDeclaration>(
declaration: D, declaration: D,
private val actualModule: Module,
private val actualPlatform: MultiTargetPlatform.Specific, private val actualPlatform: MultiTargetPlatform.Specific,
private val generateIt: KtPsiFactory.(Project, D) -> D? private val generateIt: KtPsiFactory.(Project, D) -> D?
) : KotlinQuickFixAction<D>(declaration) { ) : KotlinQuickFixAction<D>(declaration) {
@@ -55,7 +55,7 @@ sealed class CreateActualFix<out D : KtNamedDeclaration>(
protected abstract val elementType: String protected abstract val elementType: String
override fun getText() = "Create actual $elementType for platform ${actualPlatform.platform}" override fun getText() = "Create actual $elementType for module ${actualModule.name} (${actualPlatform.platform})"
override fun startInWriteAction() = false override fun startInWriteAction() = false
@@ -88,12 +88,6 @@ sealed class CreateActualFix<out D : KtNamedDeclaration>(
} }
} }
private fun implementationModuleOf(expectedModule: Module) =
expectedModule.implementingModules.firstOrNull {
PackageUtil.checkSourceRootsConfigured(it, false) &&
TargetPlatformDetector.getPlatform(it).multiTargetPlatform == actualPlatform
}
private fun getOrCreateImplementationFile(): KtFile? { private fun getOrCreateImplementationFile(): KtFile? {
val declaration = element as? KtNamedDeclaration ?: return null val declaration = element as? KtNamedDeclaration ?: return null
val parent = declaration.parent val parent = declaration.parent
@@ -101,7 +95,7 @@ sealed class CreateActualFix<out D : KtNamedDeclaration>(
for (otherDeclaration in parent.declarations) { for (otherDeclaration in parent.declarations) {
if (otherDeclaration === declaration) continue if (otherDeclaration === declaration) continue
if (!otherDeclaration.hasExpectModifier()) continue if (!otherDeclaration.hasExpectModifier()) continue
val actualDeclaration = otherDeclaration.actualsForExpected(actualPlatform).singleOrNull() ?: continue val actualDeclaration = otherDeclaration.actualsForExpected(actualModule).singleOrNull() ?: continue
return actualDeclaration.containingKtFile return actualDeclaration.containingKtFile
} }
} }
@@ -110,8 +104,6 @@ sealed class CreateActualFix<out D : KtNamedDeclaration>(
val expectedDir = declaration.containingFile.containingDirectory val expectedDir = declaration.containingFile.containingDirectory
val expectedPackage = JavaDirectoryService.getInstance().getPackage(expectedDir) val expectedPackage = JavaDirectoryService.getInstance().getPackage(expectedDir)
val expectedModule = ModuleUtilCore.findModuleForPsiElement(declaration) ?: return null
val actualModule = implementationModuleOf(expectedModule) ?: return null
val actualDirectory = PackageUtil.findOrCreateDirectoryForPackage( val actualDirectory = PackageUtil.findOrCreateDirectoryForPackage(
actualModule, expectedPackage?.qualifiedName ?: "", null, false actualModule, expectedPackage?.qualifiedName ?: "", null, false
) ?: return null ) ?: return null
@@ -147,11 +139,13 @@ sealed class CreateActualFix<out D : KtNamedDeclaration>(
val compatibility = d.c val compatibility = d.c
// For function we allow it, because overloads are possible // For function we allow it, because overloads are possible
if (compatibility.isNotEmpty() && declaration !is KtFunction) return null if (compatibility.isNotEmpty() && declaration !is KtFunction) return null
val actualPlatform = d.b.getMultiTargetPlatform() as? MultiTargetPlatform.Specific ?: return null val actualModuleDescriptor = d.b
val actualModule = (actualModuleDescriptor.getCapability(ModuleInfo.Capability) as? ModuleSourceInfo)?.module ?: return null
val actualPlatform = actualModuleDescriptor.getMultiTargetPlatform() as? MultiTargetPlatform.Specific ?: return null
return when (declaration) { return when (declaration) {
is KtClassOrObject -> CreateActualClassFix(declaration, actualPlatform) is KtClassOrObject -> CreateActualClassFix(declaration, actualModule, actualPlatform)
is KtFunction -> CreateActualFunctionFix(declaration, actualPlatform) is KtFunction -> CreateActualFunctionFix(declaration, actualModule, actualPlatform)
is KtProperty -> CreateActualPropertyFix(declaration, actualPlatform) is KtProperty -> CreateActualPropertyFix(declaration, actualModule, actualPlatform)
else -> null else -> null
} }
} }
@@ -160,8 +154,9 @@ sealed class CreateActualFix<out D : KtNamedDeclaration>(
class CreateActualClassFix( class CreateActualClassFix(
klass: KtClassOrObject, klass: KtClassOrObject,
actualModule: Module,
actualPlatform: MultiTargetPlatform.Specific actualPlatform: MultiTargetPlatform.Specific
) : CreateActualFix<KtClassOrObject>(klass, actualPlatform, { project, element -> ) : CreateActualFix<KtClassOrObject>(klass, actualModule, actualPlatform, { project, element ->
generateClassOrObjectByExpectedClass(project, element, actualNeeded = true) generateClassOrObjectByExpectedClass(project, element, actualNeeded = true)
}) { }) {
@@ -182,8 +177,9 @@ class CreateActualClassFix(
class CreateActualPropertyFix( class CreateActualPropertyFix(
property: KtProperty, property: KtProperty,
actualModule: Module,
actualPlatform: MultiTargetPlatform.Specific actualPlatform: MultiTargetPlatform.Specific
) : CreateActualFix<KtProperty>(property, actualPlatform, { project, element -> ) : CreateActualFix<KtProperty>(property, actualModule, actualPlatform, { project, element ->
val descriptor = element.toDescriptor() as? PropertyDescriptor val descriptor = element.toDescriptor() as? PropertyDescriptor
descriptor?.let { generateProperty(project, element, descriptor, actualNeeded = true) } descriptor?.let { generateProperty(project, element, descriptor, actualNeeded = true) }
}) { }) {
@@ -193,8 +189,9 @@ class CreateActualPropertyFix(
class CreateActualFunctionFix( class CreateActualFunctionFix(
function: KtFunction, function: KtFunction,
actualModule: Module,
actualPlatform: MultiTargetPlatform.Specific actualPlatform: MultiTargetPlatform.Specific
) : CreateActualFix<KtFunction>(function, actualPlatform, { project, element -> ) : CreateActualFix<KtFunction>(function, actualModule, actualPlatform, { project, element ->
val descriptor = element.toDescriptor() as? FunctionDescriptor val descriptor = element.toDescriptor() as? FunctionDescriptor
descriptor?.let { generateFunction(project, element, descriptor, actualNeeded = true) } descriptor?.let { generateFunction(project, element, descriptor, actualNeeded = true) }
}) { }) {
@@ -1,4 +1,4 @@
// "Create actual class for platform JS" "true" // "Create actual class for module js (JS)" "true"
expect abstract class <caret>Abstract { expect abstract class <caret>Abstract {
fun foo(param: String): Int fun foo(param: String): Int
@@ -1,4 +1,4 @@
// "Create actual class for platform JS" "true" // "Create actual class for module js (JS)" "true"
expect abstract class Abstract { expect abstract class Abstract {
fun foo(param: String): Int fun foo(param: String): Int
@@ -1,3 +1,3 @@
// "Create actual annotation class for platform JVM" "true" // "Create actual annotation class for module jvm (JVM)" "true"
expect annotation class <caret>Ann(val x: Int, val y: String) expect annotation class <caret>Ann(val x: Int, val y: String)
@@ -1,3 +1,3 @@
// "Create actual annotation class for platform JVM" "true" // "Create actual annotation class for module jvm (JVM)" "true"
expect annotation class Ann(val x: Int, val y: String) expect annotation class Ann(val x: Int, val y: String)
+1 -1
View File
@@ -1,4 +1,4 @@
// "Create actual class for platform JVM" "true" // "Create actual class for module jvm (JVM)" "true"
expect class <caret>My { expect class <caret>My {
fun foo(param: String): Int fun foo(param: String): Int
@@ -1,4 +1,4 @@
// "Create actual class for platform JVM" "true" // "Create actual class for module jvm (JVM)" "true"
expect class My { expect class My {
fun foo(param: String): Int fun foo(param: String): Int
+1 -1
View File
@@ -1,4 +1,4 @@
// "Create actual enum class for platform JS" "true" // "Create actual enum class for module js (JS)" "true"
expect enum class <caret>MyEnum { expect enum class <caret>MyEnum {
FIRST, FIRST,
@@ -1,4 +1,4 @@
// "Create actual enum class for platform JS" "true" // "Create actual enum class for module js (JS)" "true"
expect enum class MyEnum { expect enum class MyEnum {
FIRST, FIRST,
@@ -1,3 +1,3 @@
// "Create actual function for platform JVM" "true" // "Create actual function for module jvm (JVM)" "true"
expect fun <caret>foo(arg: Int): String expect fun <caret>foo(arg: Int): String
@@ -1,3 +1,3 @@
// "Create actual function for platform JVM" "true" // "Create actual function for module jvm (JVM)" "true"
expect fun foo(arg: Int): String expect fun foo(arg: Int): String
@@ -1,4 +1,4 @@
// "Create actual function for platform JVM" "true" // "Create actual function for module jvm (JVM)" "true"
expect fun bar() expect fun bar()
@@ -1,4 +1,4 @@
// "Create actual function for platform JVM" "true" // "Create actual function for module jvm (JVM)" "true"
expect fun bar() expect fun bar()
@@ -1,4 +1,4 @@
// "Create actual interface for platform JVM" "true" // "Create actual interface for module jvm (JVM)" "true"
expect interface <caret>Interface { expect interface <caret>Interface {
fun foo(param: String): Int fun foo(param: String): Int
@@ -1,4 +1,4 @@
// "Create actual interface for platform JVM" "true" // "Create actual interface for module jvm (JVM)" "true"
expect interface Interface { expect interface Interface {
fun foo(param: String): Int fun foo(param: String): Int
+1 -1
View File
@@ -1,4 +1,4 @@
// "Create actual class for platform JVM" "true" // "Create actual class for module jvm (JVM)" "true"
expect class <caret>WithNested { expect class <caret>WithNested {
fun foo(): Int fun foo(): Int
@@ -1,4 +1,4 @@
// "Create actual class for platform JVM" "true" // "Create actual class for module jvm (JVM)" "true"
expect class WithNested { expect class WithNested {
fun foo(): Int fun foo(): Int
+1 -1
View File
@@ -1,4 +1,4 @@
// "Create actual object for platform JVM" "true" // "Create actual object for module jvm (JVM)" "true"
expect object <caret>Object { expect object <caret>Object {
fun foo(): String fun foo(): String
@@ -1,4 +1,4 @@
// "Create actual object for platform JVM" "true" // "Create actual object for module jvm (JVM)" "true"
expect object Object { expect object Object {
fun foo(): String fun foo(): String
+1 -1
View File
@@ -1,4 +1,4 @@
// "Create actual class for platform JVM" "true" // "Create actual class for module jvm (JVM)" "true"
// SHOULD_BE_AVAILABLE_AFTER_EXECUTION // SHOULD_BE_AVAILABLE_AFTER_EXECUTION
package test.inner package test.inner
@@ -1,4 +1,4 @@
// "Create actual class for platform JVM" "true" // "Create actual class for module jvm (JVM)" "true"
// SHOULD_BE_AVAILABLE_AFTER_EXECUTION // SHOULD_BE_AVAILABLE_AFTER_EXECUTION
package test.inner package test.inner
@@ -1,4 +1,4 @@
// "Create actual class for platform JVM" "true" // "Create actual class for module jvm (JVM)" "true"
// SHOULD_BE_AVAILABLE_AFTER_EXECUTION // SHOULD_BE_AVAILABLE_AFTER_EXECUTION
package test.inner package test.inner
@@ -1,4 +1,4 @@
// "Create actual class for platform JVM" "true" // "Create actual class for module jvm (JVM)" "true"
// SHOULD_BE_AVAILABLE_AFTER_EXECUTION // SHOULD_BE_AVAILABLE_AFTER_EXECUTION
package test.inner package test.inner
@@ -1,4 +1,4 @@
// "Create actual class for platform JVM" "true" // "Create actual class for module jvm (JVM)" "true"
// SHOULD_BE_AVAILABLE_AFTER_EXECUTION // SHOULD_BE_AVAILABLE_AFTER_EXECUTION
package test.inner package test.inner
@@ -1,4 +1,4 @@
// "Create actual class for platform JVM" "true" // "Create actual class for module jvm (JVM)" "true"
// SHOULD_BE_AVAILABLE_AFTER_EXECUTION // SHOULD_BE_AVAILABLE_AFTER_EXECUTION
package test.inner package test.inner
@@ -1,3 +1,3 @@
// "Create actual class for platform JVM" "true" // "Create actual class for module jvm (JVM)" "true"
expect class <caret>WithPrimaryConstructor(x: Int, s: String) expect class <caret>WithPrimaryConstructor(x: Int, s: String)
@@ -1,3 +1,3 @@
// "Create actual class for platform JVM" "true" // "Create actual class for module jvm (JVM)" "true"
expect class WithPrimaryConstructor(x: Int, s: String) expect class WithPrimaryConstructor(x: Int, s: String)
@@ -1,3 +1,3 @@
// "Create actual property for platform JVM" "true" // "Create actual property for module jvm (JVM)" "true"
expect var <caret>x: Int expect var <caret>x: Int
@@ -1,3 +1,3 @@
// "Create actual property for platform JVM" "true" // "Create actual property for module jvm (JVM)" "true"
expect var x: Int expect var x: Int
+1 -1
View File
@@ -1,4 +1,4 @@
// "Create actual class for platform JS" "true" // "Create actual class for module js (JS)" "true"
expect sealed class <caret>Sealed { expect sealed class <caret>Sealed {
object Obj : Sealed object Obj : Sealed
@@ -1,4 +1,4 @@
// "Create actual class for platform JS" "true" // "Create actual class for module js (JS)" "true"
expect sealed class Sealed { expect sealed class Sealed {
object Obj : Sealed object Obj : Sealed
@@ -1,4 +1,4 @@
// "Create actual class for platform JS" "true" // "Create actual class for module js (JS)" "true"
expect sealed class Sealed expect sealed class Sealed
@@ -1,4 +1,4 @@
// "Create actual class for platform JS" "true" // "Create actual class for module js (JS)" "true"
expect sealed class Sealed expect sealed class Sealed
@@ -1,3 +1,3 @@
// "Create actual function for platform JVM" "true" // "Create actual function for module jvm (JVM)" "true"
expect fun <caret>foo(arg: Int): String expect fun <caret>foo(arg: Int): String
@@ -1,3 +1,3 @@
// "Create actual function for platform JVM" "true" // "Create actual function for module jvm (JVM)" "true"
expect fun foo(arg: Int): String expect fun foo(arg: Int): String
@@ -1,4 +1,4 @@
// "Create actual function for platform JVM" "true" // "Create actual function for module jvm (JVM)" "true"
// TEST // TEST
package test package test
@@ -1,4 +1,4 @@
// "Create actual function for platform JVM" "true" // "Create actual function for module jvm (JVM)" "true"
// TEST // TEST
package test package test
@@ -1,3 +1,3 @@
// "Create actual function for platform JVM" "true" // "Create actual function for module jvm (JVM)" "true"
expect fun <caret>testHelper() expect fun <caret>testHelper()
@@ -1,3 +1,3 @@
// "Create actual function for platform JVM" "true" // "Create actual function for module jvm (JVM)" "true"
expect fun testHelper() expect fun testHelper()