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) }
}) {