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
import com.intellij.openapi.project.Project
import com.intellij.openapi.vfs.VirtualFile
import com.intellij.psi.PsiDirectory
import com.intellij.psi.PsiElement
import com.intellij.psi.PsiFile
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.SpecialNames
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
fun verify(file: PsiFile): String?
val targetScope: VirtualFile?
get() = targetFile
}
interface KotlinDirectoryBasedMoveTarget : KotlinMoveTarget {
val directory: PsiDirectory?
override val targetScope: VirtualFile?
get() = super.targetScope ?: directory?.virtualFile
}
object EmptyKotlinMoveTarget: KotlinMoveTarget {
@@ -110,4 +118,6 @@ class KotlinDirectoryMoveTarget(
override fun getTargetPsiIfExists(originalPsi: PsiElement) = 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.moveFilesOrDirectories.MoveKotlinClassHandler
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.lexer.KtTokens
import org.jetbrains.kotlin.psi.*
@@ -158,7 +157,7 @@ class MoveKotlinDeclarationsProcessor(
val ktDeclaration = element.namedUnwrappedElement as? KtNamedDeclaration ?: return false
if (ktDeclaration.hasModifier(KtTokens.PRIVATE_KEYWORD)) return false
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
}
@@ -118,13 +118,8 @@ class MoveConflictChecker(
is KotlinDirectoryBasedMoveTarget -> {
val packageFqName = targetContainerFqName ?: return null
val targetDir = directory?.virtualFile ?: targetFile
val targetModuleDescriptor = if (targetDir != null) {
getModuleDescriptor(targetDir) ?: return null
}
else {
resolutionFacade.moduleDescriptor
}
val targetModuleDescriptor = targetScope?.let { getModuleDescriptor(it) ?: return null }
?: resolutionFacade.moduleDescriptor
MutablePackageFragmentDescriptor(targetModuleDescriptor, packageFqName).withSource(fakeFile)
}
@@ -171,11 +166,11 @@ class MoveConflictChecker(
// Based on RefactoringConflictsUtil.analyzeModuleConflicts
fun analyzeModuleConflictsInUsages(project: Project,
usages: Collection<UsageInfo>,
targetFile: VirtualFile,
targetScope: VirtualFile,
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) {
val element = usage.element ?: 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>) {
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) {
val referencedElementsToSkip = newConflicts.keySet().mapNotNullTo(HashSet()) { it.namedUnwrappedElement }
externalUsages.removeIf {
@@ -247,8 +242,8 @@ class MoveConflictChecker(
internalUsages: MutableSet<UsageInfo>,
conflicts: MultiMap<PsiElement, String>
) {
val targetFile = moveTarget.targetFile ?: return
val targetModule = targetFile.getModule(project) ?: return
val targetScope = moveTarget.targetScope ?: return
val targetModule = targetScope.getModule(project) ?: return
val resolveScope = targetModule.getScopeWithPlatformAwareDependencies()
fun isInScope(targetElement: PsiElement, targetDescriptor: DeclarationDescriptor): Boolean {
@@ -260,7 +255,7 @@ class MoveConflictChecker(
val renderedImportableTarget = DESCRIPTOR_RENDERER_FOR_COMPARISON.render(importableDescriptor)
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 {
moduleInfo = targetModuleInfo
targetPlatform = TargetPlatformDetector.getPlatform(targetModule)
@@ -432,8 +427,7 @@ class MoveConflictChecker(
private fun isToBeMoved(element: PsiElement): Boolean = allElementsToMove.any { it.isAncestor(element, false) }
private fun checkInternalMemberUsages(conflicts: MultiMap<PsiElement, String>) {
val sourceRoot = moveTarget.targetFile ?: return
val targetModule = ModuleUtilCore.findModuleForFile(sourceRoot, project) ?: return
val targetModule = moveTarget.getTargetModule(project) ?: return
val membersToCheck = LinkedHashSet<KtDeclaration>()
val memberCollector = object : KtVisitorVoid() {