KT-44079 [Sealed Interfaces]: move refactoring update

The idea behind this commit is that Move Refactoring should warn
developers in case their intention potentially breaks sealed
hierarchies (members must share the same module and package).

Provided algorithm has two goals:
- prevent destruction of correct hierarchies
- help in fixing broken ones
This commit is contained in:
Andrei Klunnyi
2021-01-22 14:41:19 +01:00
committed by Space
parent de3678a805
commit 690fb47cbb
116 changed files with 847 additions and 132 deletions
@@ -804,7 +804,6 @@ selected.code.fragment.has.multiple.exit.points=Selected code fragment has multi
selected.code.fragment.has.multiple.output.values=Selected code fragment has more than 3 output values:
selected.code.fragment.has.output.values.and.exit.points=Selected code fragment has output values as well as alternative exit points
setter.of.0.will.become.invisible.after.extraction=Setter of {0} will become invisible after extraction
text.0.1.must.be.moved.with.sealed.parent.class.and.all.its.subclasses={0} ''{1}'' must be moved with sealed parent class and all its subclasses
text.0.already.contains.1={0} already contains {1}
text.0.already.contains.nested.class.1={0} already contains nested class named {1}
text.0.already.declared.in.1={0} is already declared in {1}
@@ -946,7 +945,10 @@ text.rename.overloads.to=Rename overloads to:
text.rename.parameters.in.hierarchy.to=Rename parameter in hierarchy to:
text.rename.parameters.title=Rename Parameters
text.rename.warning=Rename warning
text.sealed.class.0.must.be.moved.with.all.its.subclasses=Sealed class ''{0}'' must be moved with all its subclasses
text.sealed.broken.hierarchy.none.in.target=Sealed hierarchy of ''{0}'' would be split. None of its members reside in the package ''{1}'' of module ''{2}'': {3}.
text.sealed.broken.hierarchy.still.in.source=Sealed hierarchy of ''{0}'' would be split. Package ''{1}'' of module ''{2}'' would still contain its members: {3}.
text.select.target.code.block.file=Select target code block / file
text.select.target.code.block=Select target code block
text.select.target.file=Select target file
@@ -15,6 +15,8 @@ import com.intellij.openapi.vfs.VirtualFile
import com.intellij.psi.*
import com.intellij.psi.search.GlobalSearchScope
import com.intellij.psi.search.SearchScope
import com.intellij.psi.search.searches.ClassInheritorsSearch
import com.intellij.psi.search.searches.ClassInheritorsSearch.SearchParameters
import com.intellij.psi.search.searches.ReferencesSearch
import com.intellij.psi.util.PsiTreeUtil
import com.intellij.refactoring.RefactoringBundle
@@ -23,10 +25,11 @@ import com.intellij.refactoring.util.MoveRenameUsageInfo
import com.intellij.refactoring.util.NonCodeUsageInfo
import com.intellij.refactoring.util.RefactoringUIUtil
import com.intellij.usageView.UsageInfo
import com.intellij.usageView.UsageViewTypeLocation
import com.intellij.util.containers.MultiMap
import org.jetbrains.kotlin.asJava.namedUnwrappedElement
import org.jetbrains.kotlin.asJava.toLightClass
import org.jetbrains.kotlin.asJava.toLightMethods
import org.jetbrains.kotlin.backend.common.serialization.findPackage
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.descriptors.impl.MutablePackageFragmentDescriptor
@@ -37,8 +40,13 @@ import org.jetbrains.kotlin.idea.caches.project.implementedModules
import org.jetbrains.kotlin.idea.caches.resolve.*
import org.jetbrains.kotlin.idea.caches.resolve.util.getJavaMemberDescriptor
import org.jetbrains.kotlin.idea.caches.resolve.util.hasJavaResolutionFacade
import org.jetbrains.kotlin.idea.caches.resolve.util.javaResolutionFacade
import org.jetbrains.kotlin.idea.caches.resolve.util.resolveToDescriptor
import org.jetbrains.kotlin.idea.codeInsight.DescriptorToSourceUtilsIde
import org.jetbrains.kotlin.idea.core.getPackage
import org.jetbrains.kotlin.idea.core.isInTestSourceContentKotlinAware
import org.jetbrains.kotlin.idea.core.util.toPsiDirectory
import org.jetbrains.kotlin.idea.core.util.toPsiFile
import org.jetbrains.kotlin.idea.imports.importableFqName
import org.jetbrains.kotlin.idea.project.TargetPlatformDetector
import org.jetbrains.kotlin.idea.project.forcedTargetPlatform
@@ -46,9 +54,12 @@ import org.jetbrains.kotlin.idea.refactoring.getUsageContext
import org.jetbrains.kotlin.idea.refactoring.move.KotlinMoveUsage
import org.jetbrains.kotlin.idea.refactoring.pullUp.renderForConflicts
import org.jetbrains.kotlin.idea.search.and
import org.jetbrains.kotlin.idea.search.getKotlinFqName
import org.jetbrains.kotlin.idea.search.not
import org.jetbrains.kotlin.idea.search.usagesSearch.descriptor
import org.jetbrains.kotlin.idea.util.projectStructure.getModule
import org.jetbrains.kotlin.idea.util.projectStructure.module
import org.jetbrains.kotlin.js.resolve.diagnostics.findPsi
import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.load.java.JavaDescriptorVisibilities
import org.jetbrains.kotlin.name.FqName
@@ -61,10 +72,8 @@ import org.jetbrains.kotlin.renderer.DescriptorRenderer
import org.jetbrains.kotlin.renderer.ParameterNameRenderingPolicy
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.DescriptorUtils
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameOrNull
import org.jetbrains.kotlin.resolve.descriptorUtil.getImportableDescriptor
import org.jetbrains.kotlin.resolve.descriptorUtil.getSuperClassNotAny
import org.jetbrains.kotlin.resolve.descriptorUtil.isSubclassOf
import org.jetbrains.kotlin.resolve.descriptorUtil.*
import org.jetbrains.kotlin.resolve.jvm.KotlinJavaPsiFacade
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
import org.jetbrains.kotlin.resolve.lazy.descriptors.findPackageFragmentForFile
import org.jetbrains.kotlin.resolve.source.KotlinSourceElement
@@ -522,43 +531,11 @@ class MoveConflictChecker(
}
private fun checkSealedClassMove(conflicts: MultiMap<PsiElement, String>) {
val visited = HashSet<PsiElement>()
val hierarchyChecker = SealedHierarchyChecker()
for (elementToMove in elementsToMove) {
if (!visited.add(elementToMove)) continue
if (elementToMove !is KtClassOrObject) continue
val rootClass: KtClass
val rootClassDescriptor: ClassDescriptor
if (elementToMove is KtClass && elementToMove.isSealed()) {
rootClass = elementToMove
rootClassDescriptor = rootClass.resolveToDescriptorIfAny() ?: return
} else {
val classDescriptor = elementToMove.resolveToDescriptorIfAny() ?: return
val superClassDescriptor = classDescriptor.getSuperClassNotAny() ?: return
if (superClassDescriptor.modality != Modality.SEALED) return
rootClassDescriptor = superClassDescriptor
rootClass = rootClassDescriptor.source.getPsi() as? KtClass ?: return
}
val subclasses = rootClassDescriptor.sealedSubclasses.mapNotNull { it.source.getPsi() }
if (subclasses.isEmpty()) continue
visited.add(rootClass)
visited.addAll(subclasses)
if (isToBeMoved(rootClass) && subclasses.all { isToBeMoved(it) }) continue
val message = if (elementToMove == rootClass) {
KotlinBundle.message("text.sealed.class.0.must.be.moved.with.all.its.subclasses", rootClass.name.toString())
} else {
val type = ElementDescriptionUtil.getElementDescription(elementToMove, UsageViewTypeLocation.INSTANCE).capitalize()
KotlinBundle.message(
"text.0.1.must.be.moved.with.sealed.parent.class.and.all.its.subclasses",
type,
rootClass.name.toString()
)
}
conflicts.putValue(elementToMove, message)
hierarchyChecker.reportIfMoveIsDestructive(elementToMove)?.let { conflicts.putValue(elementToMove, it) }
}
}
@@ -666,6 +643,149 @@ class MoveConflictChecker(
checkSealedClassMove(conflicts)
checkNameClashes(conflicts)
}
private inner class SealedHierarchyChecker {
private val visited: MutableSet<ClassDescriptor> = mutableSetOf()
@OptIn(ExperimentalStdlibApi::class)
fun reportIfMoveIsDestructive(classToMove: KtClassOrObject): String? {
val classToMoveDesc = classToMove.resolveToDescriptorIfAny() ?: return null
if (classToMoveDesc in visited) return null
val directSealedParents = classToMoveDesc.listDirectSealedParents()
// Not a part of sealed hierarchy?
if (!classToMoveDesc.isSealed() && directSealedParents.isEmpty())
return null
// Standalone sealed class: no sealed parents, no subclasses?
if (classToMoveDesc.isSealed() && directSealedParents.isEmpty() && classToMoveDesc.listAllSubclasses().isEmpty())
return null
// Ok, we're dealing with sealed hierarchy member
val otherHierarchyMembers = classToMoveDesc.listSealedHierarchyMembers().apply { remove(classToMove) }
assert(otherHierarchyMembers.isNotEmpty())
// Entire hierarchy is to be moved at once?
if (otherHierarchyMembers.all { isToBeMoved(it) })
return null
// Hierarchy might be split (broken) (members reside in different packages) and we shouldn't prevent intention to fix it.
// That is why it's ok to move the class to a package where at least one member of hierarchy resides. In case the hierarchy is
// fully correct all its members share the same package.
val targetModule = moveTarget.getTargetModule(project) ?: return null
val targetPackage = moveTarget.getTargetPackage() ?: return null
val className = classToMove.nameAsSafeName.asString()
if (otherHierarchyMembers.none { it.residesIn(targetModule, targetPackage) }) {
val hierarchyMembers = buildList { add(classToMove); addAll(otherHierarchyMembers) }.toNamesList()
return KotlinBundle.message(
"text.sealed.broken.hierarchy.none.in.target",
className, moveTarget.getPackageName(), targetModule.name, hierarchyMembers
)
}
// Ok, class joins at least one member of the hierarchy. But probably it leaves the package where other members still exist.
// It doesn't mean we should prevent such move but it might be good for the user to be aware of the situation.
val moduleToMoveFrom = classToMove.module ?: return null
val packageToMoveFrom = classToMoveDesc.findPsiPackage(moduleToMoveFrom) ?: return null
val membersRemainingInOriginalPackage =
otherHierarchyMembers.filter { it.residesIn(moduleToMoveFrom, packageToMoveFrom) && !isToBeMoved(it) }.toList()
if ((targetPackage != packageToMoveFrom || targetModule != moduleToMoveFrom) &&
membersRemainingInOriginalPackage.any { !isToBeMoved(it) }
) {
return KotlinBundle.message(
"text.sealed.broken.hierarchy.still.in.source",
className, packageToMoveFrom.getNameOrDefault(), moduleToMoveFrom.name, membersRemainingInOriginalPackage.toNamesList()
)
}
return null
}
private fun KtClassOrObject.residesIn(targetModule: Module, targetPackage: PsiPackage): Boolean {
val myModule = module ?: return false
val myPackage = descriptor?.findPsiPackage(myModule)
return myPackage == targetPackage && myModule == targetModule
}
private fun DeclarationDescriptor.findPsiPackage(module: Module): PsiPackage? {
val fqName = findPackage().fqName
return KotlinJavaPsiFacade.getInstance(project).findPackage(fqName.asString(), GlobalSearchScope.moduleScope(module))
}
private fun KotlinMoveTarget.getTargetPackage(): PsiPackage? {
fun tryGetPackageFromTargetContainer(): PsiPackage? {
val fqName = targetContainerFqName ?: return null
val module = getTargetModule(project) ?: return null
return KotlinJavaPsiFacade.getInstance(project).findPackage(fqName.asString(), GlobalSearchScope.moduleScope(module))
}
return (this as? KotlinDirectoryBasedMoveTarget)?.directory?.getPackage()
?: targetFile?.toPsiDirectory(project)?.getPackage()
?: targetFile?.toPsiFile(project)?.containingDirectory?.getPackage()
?: tryGetPackageFromTargetContainer()
}
private fun KotlinMoveTarget.getPackageName(): String =
targetContainerFqName?.asString()?.takeIf { it.isNotEmpty() } ?: "default" // PsiPackage might not exist by this moment
private fun PsiPackage?.getNameOrDefault(): String = this?.qualifiedName?.takeIf { it.isNotEmpty() } ?: "default"
@OptIn(ExperimentalStdlibApi::class)
private fun ClassDescriptor.listDirectSealedParents(): List<ClassDescriptor> = buildList {
getSuperClassNotAny()?.takeIf { it.isSealed() }?.let { this.add(it) }
getSuperInterfaces().filter { it.isSealed() }.let { this.addAll(it) }
}
private fun ClassDescriptor.listAllSubclasses(): List<ClassDescriptor> {
val sealedKtClass = findPsi() as? KtClassOrObject ?: return emptyList()
val lightClass = sealedKtClass.toLightClass() ?: return emptyList()
val searchScope = GlobalSearchScope.projectScope(sealedKtClass.project)
val searchParameters = SearchParameters(lightClass, searchScope, false, true, false)
return ClassInheritorsSearch.search(searchParameters)
.map mapper@{
val resolutionFacade = it.javaResolutionFacade() ?: return@mapper null
it.resolveToDescriptor(resolutionFacade)
}.filterNotNull()
.sortedBy(ClassDescriptor::getName)
}
private fun ClassDescriptor.listSealedHierarchyMembers(): MutableList<KtClassOrObject> {
fun ClassDescriptor.listMembersInternal(members: MutableList<ClassDescriptor>) {
val alreadyVisited = !visited.add(this)
if (alreadyVisited) return
if (isSealed()) {
members.add(this)
listDirectSealedParents().forEach { it.listMembersInternal(members) }
listAllSubclasses().forEach { it.listMembersInternal(members) }
} else {
val directSuperSealed = listDirectSealedParents()
if (directSuperSealed.isNotEmpty()) {
members.add(this)
directSuperSealed.forEach { it.listMembersInternal(members) }
}
}
}
val members = mutableListOf<ClassDescriptor>()
listMembersInternal(members)
return members.mapNotNull { it.findPsi() as? KtClassOrObject }.toMutableList()
}
private fun List<PsiElement>.toNamesList(): List<String> = mapNotNull { el -> el.getKotlinFqName()?.asString() }.toList()
}
}
fun analyzeConflictsInFile(
@@ -1,7 +0,0 @@
package source
import target.Expr
data class Const(val number: Double) : Expr()
data class Sum(val e1: Expr, val e2: Expr) : Expr()
object NotANumber : Expr()
@@ -1,3 +0,0 @@
package target
sealed class Expr
@@ -1,6 +0,0 @@
package source
sealed class <caret>Expr
data class Const(val number: Double) : Expr()
data class Sum(val e1: Expr, val e2: Expr) : Expr()
object NotANumber : Expr()
@@ -1 +0,0 @@
Sealed class 'Expr' must be moved with all its subclasses
@@ -1,5 +0,0 @@
{
"mainFile": "source/Foo.kt",
"type": "MOVE_KOTLIN_TOP_LEVEL_DECLARATIONS",
"targetPackage": "target"
}
@@ -1,5 +0,0 @@
package source
sealed class Expr
data class Sum(val e1: Expr, val e2: Expr) : Expr()
object NotANumber : Expr()
@@ -1,5 +0,0 @@
package target
import source.Expr
data class Const(val number: Double) : Expr()
@@ -1,6 +0,0 @@
package source
sealed class Expr
data class <caret>Const(val number: Double) : Expr()
data class Sum(val e1: Expr, val e2: Expr) : Expr()
object NotANumber : Expr()
@@ -1 +0,0 @@
Class 'Expr' must be moved with sealed parent class and all its subclasses
@@ -1,5 +0,0 @@
{
"mainFile": "source/Foo.kt",
"type": "MOVE_KOTLIN_TOP_LEVEL_DECLARATIONS",
"targetPackage": "target"
}
@@ -1,5 +0,0 @@
package bar
public sealed class SealedClass {
public class Impl1 : SealedClass() {}
}
@@ -1,5 +0,0 @@
package foo
import bar.SealedClass
val v = SealedClass::Impl1
@@ -1,5 +0,0 @@
package foo
import bar.SealedClass
public class Impl2 : SealedClass() {}
@@ -1,3 +0,0 @@
package foo
val v = SealedClass::Impl1
@@ -1,7 +0,0 @@
package foo
public sealed class <caret>SealedClass {
public class Impl1 : SealedClass() {}
}
public class Impl2 : SealedClass() {}
@@ -1 +0,0 @@
Sealed class 'SealedClass' must be moved with all its subclasses
@@ -1,5 +0,0 @@
{
"mainFile": "foo/SealedClass.kt",
"type": "MOVE_KOTLIN_TOP_LEVEL_DECLARATIONS",
"targetPackage": "bar"
}
@@ -0,0 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="JAVA_MODULE" version="4">
<component name="NewModuleRootManager" inherit-compiler-output="true">
<exclude-output />
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>
@@ -0,0 +1,6 @@
package other
sealed interface SealedInterfaceA
sealed interface SealedInterfaceB
sealed class HierarchyClassA: SealedInterfaceA, SealedInterfaceB
class NonSealedButMember: HierarchyClassA()
@@ -0,0 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="JAVA_MODULE" version="4">
<component name="NewModuleRootManager" inherit-compiler-output="true">
<exclude-output />
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>
@@ -0,0 +1,7 @@
package sealed
sealed interface <caret>SealedInterfaceA
sealed interface <caret>SealedInterfaceB
sealed class <caret>HierarchyClassA: SealedInterfaceA, SealedInterfaceB
class <caret>NonSealedButMember: HierarchyClassA()
@@ -0,0 +1,7 @@
{
"mainFile": "A/src/sealed/SealedHierarchy.kt",
"type": "MOVE_KOTLIN_TOP_LEVEL_DECLARATIONS",
"targetPackage": "other",
"targetSourceRoot": "A/src",
"withRuntime": "false"
}
@@ -0,0 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="JAVA_MODULE" version="4">
<component name="NewModuleRootManager" inherit-compiler-output="true">
<exclude-output />
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>
@@ -0,0 +1,5 @@
package other
import sealed.DerivedFromSealed
class NotSealedHierarchyMember: DerivedFromSealed()
@@ -0,0 +1,7 @@
package sealed
sealed interface SealedInterfaceA
sealed interface SealedInterfaceB
sealed class HierarchySealedClass: SealedInterfaceA, SealedInterfaceB
class DerivedFromSealed: HierarchySealedClass()
@@ -0,0 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="JAVA_MODULE" version="4">
<component name="NewModuleRootManager" inherit-compiler-output="true">
<exclude-output />
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>
@@ -0,0 +1,8 @@
package sealed
sealed interface SealedInterfaceA
sealed interface SealedInterfaceB
sealed class HierarchySealedClass: SealedInterfaceA, SealedInterfaceB
class DerivedFromSealed: HierarchySealedClass()
class <caret>NotSealedHierarchyMember: DerivedFromSealed()
@@ -0,0 +1,7 @@
{
"mainFile": "A/src/sealed/SealedHierarchy.kt",
"type": "MOVE_KOTLIN_TOP_LEVEL_DECLARATIONS",
"targetPackage": "other",
"targetSourceRoot": "A/src",
"withRuntime": "false"
}
@@ -0,0 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="JAVA_MODULE" version="4">
<component name="NewModuleRootManager" inherit-compiler-output="true">
<exclude-output />
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>
@@ -0,0 +1,3 @@
package sealedFirst
sealed interface SealedInterfaceA
@@ -0,0 +1,5 @@
package sealedSecond
import sealedFirst.SealedInterfaceA
sealed class HierarchyClassA: SealedInterfaceA, SealedInterfaceB
@@ -0,0 +1,3 @@
package sealedSecond
sealed interface SealedInterfaceB
@@ -0,0 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="JAVA_MODULE" version="4">
<component name="NewModuleRootManager" inherit-compiler-output="true">
<exclude-output />
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>
@@ -0,0 +1,6 @@
package sealedFirst
import sealedSecond.SealedInterfaceB
sealed interface SealedInterfaceA
sealed class <caret>HierarchyClassA: SealedInterfaceA, SealedInterfaceB
@@ -0,0 +1,3 @@
package sealedSecond
sealed interface SealedInterfaceB
@@ -0,0 +1 @@
Sealed hierarchy of 'HierarchyClassA' would be split. Package 'sealedFirst' of module 'A' would still contain its members: [sealedFirst.SealedInterfaceA].
@@ -0,0 +1,7 @@
{
"mainFile": "A/src/sealedFirst/SealedHierarchyPartA.kt",
"type": "MOVE_KOTLIN_TOP_LEVEL_DECLARATIONS",
"targetPackage": "sealedSecond",
"targetSourceRoot": "A/src",
"withRuntime": "false"
}
@@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="JAVA_MODULE" version="4">
<component name="NewModuleRootManager" inherit-compiler-output="true">
<exclude-output />
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
<orderEntry type="module" module-name="B" />
</component>
</module>
@@ -0,0 +1,3 @@
package sealed
sealed class HierarchyClassA: SealedInterfaceA, SealedInterfaceB
@@ -0,0 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="JAVA_MODULE" version="4">
<component name="NewModuleRootManager" inherit-compiler-output="true">
<exclude-output />
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>
@@ -0,0 +1,3 @@
package sealed
sealed interface SealedInterfaceA
@@ -0,0 +1,3 @@
package sealed
sealed interface SealedInterfaceB
@@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="JAVA_MODULE" version="4">
<component name="NewModuleRootManager" inherit-compiler-output="true">
<exclude-output />
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
<orderEntry type="module" module-name="B" />
</component>
</module>
@@ -0,0 +1,4 @@
package sealed
sealed interface <caret>SealedInterfaceA
sealed class HierarchyClassA: SealedInterfaceA, SealedInterfaceB
@@ -0,0 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="JAVA_MODULE" version="4">
<component name="NewModuleRootManager" inherit-compiler-output="true">
<exclude-output />
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>
@@ -0,0 +1,3 @@
package sealed
sealed interface SealedInterfaceB
@@ -0,0 +1 @@
Sealed hierarchy of 'SealedInterfaceA' would be split. Package 'sealed' of module 'A' would still contain its members: [sealed.HierarchyClassA].
@@ -0,0 +1,7 @@
{
"mainFile": "A/src/sealed/SealedHierarchy.kt",
"type": "MOVE_KOTLIN_TOP_LEVEL_DECLARATIONS",
"targetPackage": "sealed",
"targetSourceRoot": "B/src",
"withRuntime": "false"
}
@@ -0,0 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="JAVA_MODULE" version="4">
<component name="NewModuleRootManager" inherit-compiler-output="true">
<exclude-output />
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>
@@ -0,0 +1,3 @@
package other
sealed interface SealedInterfaceA
@@ -0,0 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="JAVA_MODULE" version="4">
<component name="NewModuleRootManager" inherit-compiler-output="true">
<exclude-output />
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>
@@ -0,0 +1,3 @@
package sealed
sealed interface <caret>SealedInterfaceA
@@ -0,0 +1,7 @@
{
"mainFile": "A/src/sealed/SealedHierarchy.kt",
"type": "MOVE_KOTLIN_TOP_LEVEL_DECLARATIONS",
"targetPackage": "other",
"targetSourceRoot": "A/src",
"withRuntime": "false"
}
@@ -0,0 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="JAVA_MODULE" version="4">
<component name="NewModuleRootManager" inherit-compiler-output="true">
<exclude-output />
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>
@@ -0,0 +1,4 @@
package sealedSecond
sealed interface SealedInterfaceA
sealed class HierarchyClassA: SealedInterfaceA, SealedInterfaceB
@@ -0,0 +1,3 @@
package sealedSecond
sealed interface SealedInterfaceB
@@ -0,0 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="JAVA_MODULE" version="4">
<component name="NewModuleRootManager" inherit-compiler-output="true">
<exclude-output />
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>
@@ -0,0 +1,6 @@
package sealedFirst
import sealedSecond.SealedInterfaceB
sealed interface <caret>SealedInterfaceA
sealed class <caret>HierarchyClassA: SealedInterfaceA, SealedInterfaceB
@@ -0,0 +1,3 @@
package sealedSecond
sealed interface SealedInterfaceB
@@ -0,0 +1,7 @@
{
"mainFile": "A/src/sealedFirst/SealedHierarchyPartA.kt",
"type": "MOVE_KOTLIN_TOP_LEVEL_DECLARATIONS",
"targetPackage": "sealedSecond",
"targetSourceRoot": "A/src",
"withRuntime": "false"
}
@@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="JAVA_MODULE" version="4">
<component name="NewModuleRootManager" inherit-compiler-output="true">
<exclude-output />
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
<orderEntry type="module" module-name="B" />
</component>
</module>
@@ -0,0 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="JAVA_MODULE" version="4">
<component name="NewModuleRootManager" inherit-compiler-output="true">
<exclude-output />
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>
@@ -0,0 +1,4 @@
package sealed
sealed interface SealedInterfaceA
sealed class HierarchyClassA: SealedInterfaceA, SealedInterfaceB
@@ -0,0 +1,3 @@
package sealed
sealed interface SealedInterfaceB
@@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="JAVA_MODULE" version="4">
<component name="NewModuleRootManager" inherit-compiler-output="true">
<exclude-output />
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
<orderEntry type="module" module-name="B" />
</component>
</module>
@@ -0,0 +1,4 @@
package sealed
sealed interface <caret>SealedInterfaceA
sealed class <caret>HierarchyClassA: SealedInterfaceA, SealedInterfaceB
@@ -0,0 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="JAVA_MODULE" version="4">
<component name="NewModuleRootManager" inherit-compiler-output="true">
<exclude-output />
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>
@@ -0,0 +1,3 @@
package sealed
sealed interface SealedInterfaceB
@@ -0,0 +1,7 @@
{
"mainFile": "A/src/sealed/SealedHierarchy.kt",
"type": "MOVE_KOTLIN_TOP_LEVEL_DECLARATIONS",
"targetPackage": "sealed",
"targetSourceRoot": "B/src",
"withRuntime": "false"
}
@@ -0,0 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="JAVA_MODULE" version="4">
<component name="NewModuleRootManager" inherit-compiler-output="true">
<exclude-output />
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>
@@ -0,0 +1,6 @@
package another
import sealed.SealedInterfaceA
import sealed.SealedInterfaceB
class HierarchyClassA: SealedInterfaceA, SealedInterfaceB
@@ -0,0 +1,5 @@
package sealed
sealed interface SealedInterfaceA
sealed interface SealedInterfaceB
@@ -0,0 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="JAVA_MODULE" version="4">
<component name="NewModuleRootManager" inherit-compiler-output="true">
<exclude-output />
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>
@@ -0,0 +1,6 @@
package sealed
sealed interface SealedInterfaceA
sealed interface SealedInterfaceB
class <caret>HierarchyClassA: SealedInterfaceA, SealedInterfaceB
@@ -0,0 +1 @@
Sealed hierarchy of 'HierarchyClassA' would be split. None of its members reside in the package 'another' of module 'A': [sealed.HierarchyClassA, sealed.SealedInterfaceA, sealed.SealedInterfaceB].
@@ -0,0 +1,7 @@
{
"mainFile": "A/src/sealed/SealedHierarchy.kt",
"type": "MOVE_KOTLIN_TOP_LEVEL_DECLARATIONS",
"targetPackage": "another",
"targetSourceRoot": "A/src",
"withRuntime": "false"
}
@@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="JAVA_MODULE" version="4">
<component name="NewModuleRootManager" inherit-compiler-output="true">
<exclude-output />
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
<orderEntry type="module" module-name="B" />
</component>
</module>
@@ -0,0 +1,5 @@
package sealed
sealed interface SealedInterfaceB
class HierarchyClassA: SealedInterfaceA, SealedInterfaceB
@@ -0,0 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="JAVA_MODULE" version="4">
<component name="NewModuleRootManager" inherit-compiler-output="true">
<exclude-output />
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>
@@ -0,0 +1,3 @@
package sealed
interface HelloGitEmptyDir
@@ -0,0 +1,3 @@
package sealed
sealed interface SealedInterfaceA
@@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="JAVA_MODULE" version="4">
<component name="NewModuleRootManager" inherit-compiler-output="true">
<exclude-output />
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
<orderEntry type="module" module-name="B" />
</component>
</module>
@@ -0,0 +1,6 @@
package sealed
sealed interface <caret>SealedInterfaceA
sealed interface SealedInterfaceB
class HierarchyClassA: SealedInterfaceA, SealedInterfaceB
@@ -0,0 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="JAVA_MODULE" version="4">
<component name="NewModuleRootManager" inherit-compiler-output="true">
<exclude-output />
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>
@@ -0,0 +1,3 @@
package sealed
interface HelloGitEmptyDir
@@ -0,0 +1 @@
Sealed hierarchy of 'SealedInterfaceA' would be split. None of its members reside in the package 'sealed' of module 'B': [sealed.SealedInterfaceA, sealed.HierarchyClassA, sealed.SealedInterfaceB].
@@ -0,0 +1,7 @@
{
"mainFile": "A/src/sealed/SealedHierarchy.kt",
"type": "MOVE_KOTLIN_TOP_LEVEL_DECLARATIONS",
"targetPackage": "sealed",
"targetSourceRoot": "B/src",
"withRuntime": "false"
}
@@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="JAVA_MODULE" version="4">
<component name="NewModuleRootManager" inherit-compiler-output="true">
<exclude-output />
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
<orderEntry type="module" module-name="B" />
</component>
</module>
@@ -0,0 +1,17 @@
package sealed
sealed interface SealedInterfaceB
sealed interface SealedInterfaceC
sealed interface SealedInterfaceD: InterfaceI, SealedInterfaceA, SealedInterfaceB, SealedInterfaceC
interface InterfaceE: SealedInterfaceD
sealed interface SealedInterfaceF: InterfaceE
sealed interface SealedInterfaceG
interface InterfaceH: InterfaceE
interface InterfaceI
class ClassA: InterfaceE
class ClassC
sealed class SealedClassB: SealedInterfaceB, SealedInterfaceC, ClassC()
class ClassD: SealedClassB()
sealed class SealedClassE: SealedClassB(), SealedInterfaceG
class ClassF: ClassD()
@@ -0,0 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="JAVA_MODULE" version="4">
<component name="NewModuleRootManager" inherit-compiler-output="true">
<exclude-output />
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>

Some files were not shown because too many files have changed in this diff Show More