Create actual: put top-level actual declarations in the same file

When multiple expect declarations are in the same file,
and some of them already have actual declarations for this platform,
then "Create actual fix" put other declarations into the same file
with existing actual declarations

So #KT-17058 Fixed
So #KT-21082 Fixed
This commit is contained in:
Mikhail Glukhikh
2018-03-02 15:37:59 +03:00
parent 3ec2dac10b
commit 90e4413fc9
11 changed files with 83 additions and 13 deletions
@@ -21,6 +21,7 @@ import com.intellij.ide.util.DefaultPsiElementCellRenderer
import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.descriptors.*
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
@@ -29,6 +30,7 @@ import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils
import org.jetbrains.kotlin.resolve.MultiTargetPlatform
import org.jetbrains.kotlin.resolve.descriptorUtil.module
import org.jetbrains.kotlin.resolve.getMultiTargetPlatform
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
import org.jetbrains.kotlin.resolve.multiplatform.ExpectedActualResolver
import java.awt.event.MouseEvent
@@ -87,8 +89,11 @@ private fun DeclarationDescriptor.actualsForExpected(): Collection<DeclarationDe
return emptyList()
}
internal fun KtDeclaration.actualsForExpected(): Set<KtDeclaration> {
return unsafeResolveToDescriptor().actualsForExpected().mapNotNullTo(LinkedHashSet()) {
DescriptorToSourceUtils.descriptorToDeclaration(it) as? KtDeclaration
}
}
// null means "any platform" here
internal fun KtDeclaration.actualsForExpected(platform: MultiTargetPlatform? = null): Set<KtDeclaration> =
resolveToDescriptorIfAny(BodyResolveMode.FULL)
?.actualsForExpected()
?.filter { platform == null || it.module.getMultiTargetPlatform() == platform }
?.mapNotNullTo(LinkedHashSet()) {
DescriptorToSourceUtils.descriptorToDeclaration(it) as? KtDeclaration
} ?: emptySet()
@@ -32,6 +32,7 @@ import org.jetbrains.kotlin.diagnostics.DiagnosticFactory
import org.jetbrains.kotlin.diagnostics.Errors
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
@@ -40,6 +41,7 @@ import org.jetbrains.kotlin.idea.util.IdeDescriptorRenderers
import org.jetbrains.kotlin.idea.util.application.runWriteAction
import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.hasExpectModifier
import org.jetbrains.kotlin.resolve.MultiTargetPlatform
import org.jetbrains.kotlin.resolve.getMultiTargetPlatform
@@ -94,6 +96,15 @@ sealed class CreateActualFix<out D : KtNamedDeclaration>(
private fun getOrCreateImplementationFile(): KtFile? {
val declaration = element as? KtNamedDeclaration ?: return null
val parent = declaration.parent
if (parent is KtFile) {
for (otherDeclaration in parent.declarations) {
if (otherDeclaration === declaration) continue
if (!otherDeclaration.hasExpectModifier()) continue
val actualDeclaration = otherDeclaration.actualsForExpected(actualPlatform).singleOrNull() ?: continue
return actualDeclaration.containingKtFile
}
}
val name = declaration.name ?: return null
val expectedDir = declaration.containingFile.containingDirectory