Move: Correctly determine target module for deferred files

This commit is contained in:
Alexey Sedunov
2017-12-22 12:52:24 +03:00
parent 253c5f2d9b
commit 9d1fbbd1c6
3 changed files with 23 additions and 20 deletions
@@ -16,11 +16,13 @@
package org.jetbrains.kotlin.idea.refactoring.move.moveDeclarations package org.jetbrains.kotlin.idea.refactoring.move.moveDeclarations
import com.intellij.openapi.project.Project
import com.intellij.openapi.vfs.VirtualFile import com.intellij.openapi.vfs.VirtualFile
import com.intellij.psi.PsiDirectory import com.intellij.psi.PsiDirectory
import com.intellij.psi.PsiElement import com.intellij.psi.PsiElement
import com.intellij.psi.PsiFile import com.intellij.psi.PsiFile
import org.jetbrains.kotlin.idea.core.getOrCreateCompanionObject import org.jetbrains.kotlin.idea.core.getOrCreateCompanionObject
import org.jetbrains.kotlin.idea.util.projectStructure.getModule
import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.SpecialNames import org.jetbrains.kotlin.name.SpecialNames
import org.jetbrains.kotlin.psi.KtClass import org.jetbrains.kotlin.psi.KtClass
@@ -38,10 +40,16 @@ interface KotlinMoveTarget {
// Check possible errors and return corresponding message, or null if no errors are detected // Check possible errors and return corresponding message, or null if no errors are detected
fun verify(file: PsiFile): String? fun verify(file: PsiFile): String?
val targetScope: VirtualFile?
get() = targetFile
} }
interface KotlinDirectoryBasedMoveTarget : KotlinMoveTarget { interface KotlinDirectoryBasedMoveTarget : KotlinMoveTarget {
val directory: PsiDirectory? val directory: PsiDirectory?
override val targetScope: VirtualFile?
get() = super.targetScope ?: directory?.virtualFile
} }
object EmptyKotlinMoveTarget: KotlinMoveTarget { object EmptyKotlinMoveTarget: KotlinMoveTarget {
@@ -111,3 +119,5 @@ class KotlinDirectoryMoveTarget(
override fun verify(file: PsiFile) = null override fun verify(file: PsiFile) = null
} }
fun KotlinMoveTarget.getTargetModule(project: Project) = targetScope?.getModule(project)
@@ -49,7 +49,6 @@ import org.jetbrains.kotlin.idea.refactoring.fqName.getKotlinFqName
import org.jetbrains.kotlin.idea.refactoring.move.* import org.jetbrains.kotlin.idea.refactoring.move.*
import org.jetbrains.kotlin.idea.refactoring.move.moveFilesOrDirectories.MoveKotlinClassHandler import org.jetbrains.kotlin.idea.refactoring.move.moveFilesOrDirectories.MoveKotlinClassHandler
import org.jetbrains.kotlin.idea.search.projectScope import org.jetbrains.kotlin.idea.search.projectScope
import org.jetbrains.kotlin.idea.util.projectStructure.getModule
import org.jetbrains.kotlin.idea.util.projectStructure.module import org.jetbrains.kotlin.idea.util.projectStructure.module
import org.jetbrains.kotlin.lexer.KtTokens import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.*
@@ -158,7 +157,7 @@ class MoveKotlinDeclarationsProcessor(
val ktDeclaration = element.namedUnwrappedElement as? KtNamedDeclaration ?: return false val ktDeclaration = element.namedUnwrappedElement as? KtNamedDeclaration ?: return false
if (ktDeclaration.hasModifier(KtTokens.PRIVATE_KEYWORD)) return false if (ktDeclaration.hasModifier(KtTokens.PRIVATE_KEYWORD)) return false
val (oldContainer, newContainer) = descriptor.delegate.getContainerChangeInfo(ktDeclaration, descriptor.moveTarget) val (oldContainer, newContainer) = descriptor.delegate.getContainerChangeInfo(ktDeclaration, descriptor.moveTarget)
val targetModule = descriptor.moveTarget.targetFile?.getModule(project) ?: return false val targetModule = descriptor.moveTarget.getTargetModule(project) ?: return false
return oldContainer == newContainer && ktDeclaration.module == targetModule return oldContainer == newContainer && ktDeclaration.module == targetModule
} }
@@ -118,13 +118,8 @@ class MoveConflictChecker(
is KotlinDirectoryBasedMoveTarget -> { is KotlinDirectoryBasedMoveTarget -> {
val packageFqName = targetContainerFqName ?: return null val packageFqName = targetContainerFqName ?: return null
val targetDir = directory?.virtualFile ?: targetFile val targetModuleDescriptor = targetScope?.let { getModuleDescriptor(it) ?: return null }
val targetModuleDescriptor = if (targetDir != null) { ?: resolutionFacade.moduleDescriptor
getModuleDescriptor(targetDir) ?: return null
}
else {
resolutionFacade.moduleDescriptor
}
MutablePackageFragmentDescriptor(targetModuleDescriptor, packageFqName).withSource(fakeFile) MutablePackageFragmentDescriptor(targetModuleDescriptor, packageFqName).withSource(fakeFile)
} }
@@ -171,11 +166,11 @@ class MoveConflictChecker(
// Based on RefactoringConflictsUtil.analyzeModuleConflicts // Based on RefactoringConflictsUtil.analyzeModuleConflicts
fun analyzeModuleConflictsInUsages(project: Project, fun analyzeModuleConflictsInUsages(project: Project,
usages: Collection<UsageInfo>, usages: Collection<UsageInfo>,
targetFile: VirtualFile, targetScope: VirtualFile,
conflicts: MultiMap<PsiElement, String>) { conflicts: MultiMap<PsiElement, String>) {
val targetModule = targetFile.getModule(project) ?: return val targetModule = targetScope.getModule(project) ?: return
val isInTestSources = ModuleRootManager.getInstance(targetModule).fileIndex.isInTestSourceContent(targetFile) val isInTestSources = ModuleRootManager.getInstance(targetModule).fileIndex.isInTestSourceContent(targetScope)
NextUsage@ for (usage in usages) { NextUsage@ for (usage in usages) {
val element = usage.element ?: continue val element = usage.element ?: continue
if (PsiTreeUtil.getParentOfType(element, PsiImportStatement::class.java, false) != null) continue if (PsiTreeUtil.getParentOfType(element, PsiImportStatement::class.java, false) != null) continue
@@ -205,9 +200,9 @@ class MoveConflictChecker(
fun checkModuleConflictsInUsages(externalUsages: MutableSet<UsageInfo>, conflicts: MultiMap<PsiElement, String>) { fun checkModuleConflictsInUsages(externalUsages: MutableSet<UsageInfo>, conflicts: MultiMap<PsiElement, String>) {
val newConflicts = MultiMap<PsiElement, String>() val newConflicts = MultiMap<PsiElement, String>()
val targetFile = moveTarget.targetFile ?: return val targetScope = moveTarget.targetScope ?: return
analyzeModuleConflictsInUsages(project, externalUsages, targetFile, newConflicts) analyzeModuleConflictsInUsages(project, externalUsages, targetScope, newConflicts)
if (!newConflicts.isEmpty) { if (!newConflicts.isEmpty) {
val referencedElementsToSkip = newConflicts.keySet().mapNotNullTo(HashSet()) { it.namedUnwrappedElement } val referencedElementsToSkip = newConflicts.keySet().mapNotNullTo(HashSet()) { it.namedUnwrappedElement }
externalUsages.removeIf { externalUsages.removeIf {
@@ -247,8 +242,8 @@ class MoveConflictChecker(
internalUsages: MutableSet<UsageInfo>, internalUsages: MutableSet<UsageInfo>,
conflicts: MultiMap<PsiElement, String> conflicts: MultiMap<PsiElement, String>
) { ) {
val targetFile = moveTarget.targetFile ?: return val targetScope = moveTarget.targetScope ?: return
val targetModule = targetFile.getModule(project) ?: return val targetModule = targetScope.getModule(project) ?: return
val resolveScope = targetModule.getScopeWithPlatformAwareDependencies() val resolveScope = targetModule.getScopeWithPlatformAwareDependencies()
fun isInScope(targetElement: PsiElement, targetDescriptor: DeclarationDescriptor): Boolean { fun isInScope(targetElement: PsiElement, targetDescriptor: DeclarationDescriptor): Boolean {
@@ -260,7 +255,7 @@ class MoveConflictChecker(
val renderedImportableTarget = DESCRIPTOR_RENDERER_FOR_COMPARISON.render(importableDescriptor) val renderedImportableTarget = DESCRIPTOR_RENDERER_FOR_COMPARISON.render(importableDescriptor)
val renderedTarget by lazy { DESCRIPTOR_RENDERER_FOR_COMPARISON.render(targetDescriptor) } val renderedTarget by lazy { DESCRIPTOR_RENDERER_FOR_COMPARISON.render(targetDescriptor) }
val targetModuleInfo = getModuleInfoByVirtualFile(project, targetFile) val targetModuleInfo = getModuleInfoByVirtualFile(project, targetScope)
val dummyFile = KtPsiFactory(targetElement.project).createFile("dummy.kt", "").apply { val dummyFile = KtPsiFactory(targetElement.project).createFile("dummy.kt", "").apply {
moduleInfo = targetModuleInfo moduleInfo = targetModuleInfo
targetPlatform = TargetPlatformDetector.getPlatform(targetModule) targetPlatform = TargetPlatformDetector.getPlatform(targetModule)
@@ -432,8 +427,7 @@ class MoveConflictChecker(
private fun isToBeMoved(element: PsiElement): Boolean = allElementsToMove.any { it.isAncestor(element, false) } private fun isToBeMoved(element: PsiElement): Boolean = allElementsToMove.any { it.isAncestor(element, false) }
private fun checkInternalMemberUsages(conflicts: MultiMap<PsiElement, String>) { private fun checkInternalMemberUsages(conflicts: MultiMap<PsiElement, String>) {
val sourceRoot = moveTarget.targetFile ?: return val targetModule = moveTarget.getTargetModule(project) ?: return
val targetModule = ModuleUtilCore.findModuleForFile(sourceRoot, project) ?: return
val membersToCheck = LinkedHashSet<KtDeclaration>() val membersToCheck = LinkedHashSet<KtDeclaration>()
val memberCollector = object : KtVisitorVoid() { val memberCollector = object : KtVisitorVoid() {