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.ide.util.DefaultPsiElementCellRenderer
import com.intellij.openapi.module.Module
import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.analyzer.ModuleInfo
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.resolveToDescriptorIfAny
import org.jetbrains.kotlin.idea.caches.resolve.unsafeResolveToDescriptor
import org.jetbrains.kotlin.idea.core.toDescriptor
import org.jetbrains.kotlin.idea.facet.implementingDescriptors
import org.jetbrains.kotlin.psi.KtDeclaration
@@ -90,10 +92,10 @@ private fun DeclarationDescriptor.actualsForExpected(): Collection<DeclarationDe
}
// 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)
?.actualsForExpected()
?.filter { platform == null || it.module.getMultiTargetPlatform() == platform }
?.filter { module == null || (it.module.getCapability(ModuleInfo.Capability) as? ModuleSourceInfo)?.module == module }
?.mapNotNullTo(LinkedHashSet()) {
DescriptorToSourceUtils.descriptorToDeclaration(it) as? KtDeclaration
} ?: emptySet()
@@ -21,19 +21,18 @@ import com.intellij.ide.util.EditorHelper
import com.intellij.ide.util.PackageUtil
import com.intellij.openapi.editor.Editor
import com.intellij.openapi.module.Module
import com.intellij.openapi.module.ModuleUtilCore
import com.intellij.openapi.project.Project
import com.intellij.psi.JavaDirectoryService
import com.intellij.psi.codeStyle.CodeStyleManager
import org.jetbrains.kotlin.analyzer.ModuleInfo
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.diagnostics.Diagnostic
import org.jetbrains.kotlin.diagnostics.DiagnosticFactory
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.facet.implementingModules
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.KotlinSingleIntentionActionFactory
import org.jetbrains.kotlin.idea.refactoring.createKotlinFile
@@ -47,6 +46,7 @@ import org.jetbrains.kotlin.resolve.getMultiTargetPlatform
sealed class CreateActualFix<out D : KtNamedDeclaration>(
declaration: D,
private val actualModule: Module,
private val actualPlatform: MultiTargetPlatform.Specific,
private val generateIt: KtPsiFactory.(Project, D) -> D?
) : KotlinQuickFixAction<D>(declaration) {
@@ -55,7 +55,7 @@ sealed class CreateActualFix<out D : KtNamedDeclaration>(
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
@@ -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? {
val declaration = element as? KtNamedDeclaration ?: return null
val parent = declaration.parent
@@ -101,7 +95,7 @@ sealed class CreateActualFix<out D : KtNamedDeclaration>(
for (otherDeclaration in parent.declarations) {
if (otherDeclaration === declaration) continue
if (!otherDeclaration.hasExpectModifier()) continue
val actualDeclaration = otherDeclaration.actualsForExpected(actualPlatform).singleOrNull() ?: continue
val actualDeclaration = otherDeclaration.actualsForExpected(actualModule).singleOrNull() ?: continue
return actualDeclaration.containingKtFile
}
}
@@ -110,8 +104,6 @@ sealed class CreateActualFix<out D : KtNamedDeclaration>(
val expectedDir = declaration.containingFile.containingDirectory
val expectedPackage = JavaDirectoryService.getInstance().getPackage(expectedDir)
val expectedModule = ModuleUtilCore.findModuleForPsiElement(declaration) ?: return null
val actualModule = implementationModuleOf(expectedModule) ?: return null
val actualDirectory = PackageUtil.findOrCreateDirectoryForPackage(
actualModule, expectedPackage?.qualifiedName ?: "", null, false
) ?: return null
@@ -147,11 +139,13 @@ sealed class CreateActualFix<out D : KtNamedDeclaration>(
val compatibility = d.c
// For function we allow it, because overloads are possible
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) {
is KtClassOrObject -> CreateActualClassFix(declaration, actualPlatform)
is KtFunction -> CreateActualFunctionFix(declaration, actualPlatform)
is KtProperty -> CreateActualPropertyFix(declaration, actualPlatform)
is KtClassOrObject -> CreateActualClassFix(declaration, actualModule, actualPlatform)
is KtFunction -> CreateActualFunctionFix(declaration, actualModule, actualPlatform)
is KtProperty -> CreateActualPropertyFix(declaration, actualModule, actualPlatform)
else -> null
}
}
@@ -160,8 +154,9 @@ sealed class CreateActualFix<out D : KtNamedDeclaration>(
class CreateActualClassFix(
klass: KtClassOrObject,
actualModule: Module,
actualPlatform: MultiTargetPlatform.Specific
) : CreateActualFix<KtClassOrObject>(klass, actualPlatform, { project, element ->
) : CreateActualFix<KtClassOrObject>(klass, actualModule, actualPlatform, { project, element ->
generateClassOrObjectByExpectedClass(project, element, actualNeeded = true)
}) {
@@ -182,8 +177,9 @@ class CreateActualClassFix(
class CreateActualPropertyFix(
property: KtProperty,
actualModule: Module,
actualPlatform: MultiTargetPlatform.Specific
) : CreateActualFix<KtProperty>(property, actualPlatform, { project, element ->
) : CreateActualFix<KtProperty>(property, actualModule, actualPlatform, { project, element ->
val descriptor = element.toDescriptor() as? PropertyDescriptor
descriptor?.let { generateProperty(project, element, descriptor, actualNeeded = true) }
}) {
@@ -193,8 +189,9 @@ class CreateActualPropertyFix(
class CreateActualFunctionFix(
function: KtFunction,
actualModule: Module,
actualPlatform: MultiTargetPlatform.Specific
) : CreateActualFix<KtFunction>(function, actualPlatform, { project, element ->
) : CreateActualFix<KtFunction>(function, actualModule, actualPlatform, { project, element ->
val descriptor = element.toDescriptor() as? FunctionDescriptor
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 {
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 {
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)
@@ -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)
+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 {
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 {
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 {
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 {
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
@@ -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
@@ -1,4 +1,4 @@
// "Create actual function for platform JVM" "true"
// "Create actual function for module jvm (JVM)" "true"
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()
@@ -1,4 +1,4 @@
// "Create actual interface for platform JVM" "true"
// "Create actual interface for module jvm (JVM)" "true"
expect interface <caret>Interface {
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 {
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 {
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 {
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 {
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 {
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
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
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
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
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
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
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)
@@ -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)
@@ -1,3 +1,3 @@
// "Create actual property for platform JVM" "true"
// "Create actual property for module jvm (JVM)" "true"
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
+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 {
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 {
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
@@ -1,4 +1,4 @@
// "Create actual class for platform JS" "true"
// "Create actual class for module js (JS)" "true"
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
@@ -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
@@ -1,4 +1,4 @@
// "Create actual function for platform JVM" "true"
// "Create actual function for module jvm (JVM)" "true"
// TEST
package test
@@ -1,4 +1,4 @@
// "Create actual function for platform JVM" "true"
// "Create actual function for module jvm (JVM)" "true"
// 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()
@@ -1,3 +1,3 @@
// "Create actual function for platform JVM" "true"
// "Create actual function for module jvm (JVM)" "true"
expect fun testHelper()