Compare commits

...

13 Commits

Author SHA1 Message Date
Alexey Sedunov
11e9e7b552 Move: Fix ClassCastException on processing of callable references to Java methods
#KT-16809 Fixed
2017-03-22 00:07:17 +03:00
Alexey Sedunov
2f95131368 Move: Filter out ConflictUsageInfo instances before running the refactoring
#KT-16556 Fixed
2017-03-22 00:07:16 +03:00
Alexey Sedunov
d6599c8b83 Move: Fix NPE on moving directory where at least one Kotlin file contains package directive unmatched by the containing directory
#KT-8955 Fixed
2017-03-22 00:07:15 +03:00
Alexey Sedunov
048d1c0365 Move: Get element listener before original declaration is invalidated by the refactoring 2017-03-22 00:07:14 +03:00
Alexey Sedunov
cd1420f7c1 Move: Fix incorrect FqName when moving declaration to default package
#KT-15586 Fixed
2017-03-22 00:07:13 +03:00
Alexey Sedunov
4bcde41e8c Move: Avoid temporary file rename if the current name doesn't conflict with other files in the target directory. Improve protection against exceptions during the refactoring which may prevent final rename 2017-03-22 00:07:12 +03:00
Alexey Sedunov
6b6736fd55 Move: Do not report conflict on usages of inherited protected members
#KT-15190 Fixed
2017-03-22 00:07:11 +03:00
Alexey Sedunov
b67a77404e Move: Implement conflict checking for internal members
#KT-13190 Fixed
2017-03-22 00:07:10 +03:00
Alexey Sedunov
f186e9f11f Move: Fix processing of references to non-real (fake override, etc.) members of companion object
#KT-15559 Fixed
2017-03-22 00:07:09 +03:00
Alexey Sedunov
d774807204 Implement post-refactoring optimization of unused imports
#KT-15822 Fixed
 #KT-13755 Fixed
2017-03-22 00:07:08 +03:00
Alexey Sedunov
a4e35011e4 Move: Check that constructor call corresponds to class being moved before
transforming outer instance to argument (fixes tests broken after the
commit before)
2017-03-22 00:07:07 +03:00
Alexey Sedunov
d14f341187 Move: Exclude conflict-associated usages from refactoring. Move file internal usages search to MoveKotlinDeclarationsProcessor 2017-03-22 00:07:06 +03:00
Alexey Sedunov
6cbdb53433 Move: Use Kotlin declaration mover on KtFile because existing file mover
does not process conflicts
 #KT-13911 Fixed
2017-03-22 00:07:05 +03:00
162 changed files with 993 additions and 298 deletions

View File

@@ -358,6 +358,7 @@
<lang.unwrapDescriptor language="kotlin" implementationClass="org.jetbrains.kotlin.idea.codeInsight.unwrap.KotlinUnwrapDescriptor"/>
<quoteHandler fileType="Kotlin" className="org.jetbrains.kotlin.idea.editor.KotlinQuoteHandler"/>
<refactoring.helper implementation="org.jetbrains.kotlin.idea.codeInsight.KotlinShortenReferencesRefactoringHelper"/>
<refactoring.helper implementation="org.jetbrains.kotlin.idea.codeInsight.KotlinOptimizeImportsRefactoringHelper"/>
<refactoring.moveHandler
id="kotlin.moveFilesOrDirectories"
implementation="org.jetbrains.kotlin.idea.refactoring.move.moveFilesOrDirectories.KotlinMoveFilesOrDirectoriesHandler"

View File

@@ -0,0 +1,123 @@
/*
* Copyright 2010-2017 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.idea.codeInsight
import com.intellij.openapi.diagnostic.Logger
import com.intellij.openapi.progress.ProgressManager
import com.intellij.openapi.project.DumbService
import com.intellij.openapi.project.Project
import com.intellij.psi.PsiDocumentManager
import com.intellij.psi.SmartPsiElementPointer
import com.intellij.psi.codeStyle.CodeStyleManager
import com.intellij.refactoring.RefactoringHelper
import com.intellij.usageView.UsageInfo
import com.intellij.util.IncorrectOperationException
import com.intellij.util.SequentialModalProgressTask
import com.intellij.util.SequentialTask
import com.intellij.util.containers.HashSet
import org.jetbrains.kotlin.idea.inspections.KotlinUnusedImportInspection
import org.jetbrains.kotlin.idea.util.application.runWriteAction
import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.psi.KtImportDirective
import org.jetbrains.kotlin.psi.psiUtil.createSmartPointer
// Based on com.intellij.refactoring.OptimizeImportsRefactoringHelper
class KotlinOptimizeImportsRefactoringHelper : RefactoringHelper<Set<KtFile>> {
internal class OptimizeImportsTask(
private val task: SequentialModalProgressTask,
pointers: Set<SmartPsiElementPointer<KtImportDirective>>
) : SequentialTask {
private val pointerIterator = pointers.iterator()
private val myTotal: Int = pointers.size
private var myCount: Int = 0
override fun prepare() {}
override fun isDone() = !pointerIterator.hasNext()
override fun iteration(): Boolean {
task.indicator?.fraction = myCount++.toDouble() / myTotal
val pointer = pointerIterator.next()
val directive = pointer.element
if (directive == null || !directive.isValid) return isDone
try {
directive.delete()
}
catch (e: IncorrectOperationException) {
LOG.error(e)
}
return isDone
}
override fun stop() {}
companion object {
private val LOG = Logger.getInstance("#" + OptimizeImportsTask::class.java.name)
}
}
companion object {
private val REMOVING_REDUNDANT_IMPORTS_TITLE = "Removing redundant imports"
}
override fun prepareOperation(usages: Array<UsageInfo>): Set<KtFile> {
return usages.mapNotNullTo(LinkedHashSet<KtFile>()) {
if (!it.isNonCodeUsage) it.file as? KtFile else null
}
}
override fun performOperation(project: Project, operationData: Set<KtFile>) {
CodeStyleManager.getInstance(project).performActionWithFormatterDisabled {
PsiDocumentManager.getInstance(project).commitAllDocuments()
}
if (operationData.isEmpty()) return
val unusedImports = HashSet<SmartPsiElementPointer<KtImportDirective>>()
val findRedundantImports = {
DumbService.getInstance(project).runReadActionInSmartMode {
val progressIndicator = ProgressManager.getInstance().progressIndicator
val fileCount = operationData.size
for ((i, file) in operationData.withIndex()) {
if (!file.isValid) continue
val virtualFile = file.virtualFile ?: continue
progressIndicator?.text2 = virtualFile.presentableUrl
progressIndicator?.fraction = i.toDouble() / fileCount
val fileImportData = KotlinUnusedImportInspection.analyzeImports(file) ?: continue
fileImportData.unusedImports.mapTo(unusedImports) { it.createSmartPointer() }
}
}
}
if (!ProgressManager.getInstance().runProcessWithProgressSynchronously(
findRedundantImports, REMOVING_REDUNDANT_IMPORTS_TITLE, false, project
)) return
runWriteAction {
val progressTask = SequentialModalProgressTask(project, REMOVING_REDUNDANT_IMPORTS_TITLE, false).apply {
setMinIterationTime(200)
setTask(OptimizeImportsTask(this, unusedImports))
}
ProgressManager.getInstance().run(progressTask)
}
}
}

View File

@@ -48,78 +48,94 @@ import org.jetbrains.kotlin.idea.imports.importableFqName
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.psi.KtCodeFragment
import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.psi.KtImportDirective
import org.jetbrains.kotlin.resolve.ImportPath
import java.util.*
class KotlinUnusedImportInspection : AbstractKotlinInspection() {
data class ImportData(
val unusedImports: List<KtImportDirective>,
val optimizerData: OptimizedImportsBuilder.InputData
)
companion object {
fun analyzeImports(file: KtFile): ImportData? {
if (file is KtCodeFragment) return null
if (!file.manager.isInProject(file)) return null
if (file.importDirectives.isEmpty()) return null
val optimizerData = KotlinImportOptimizer.collectDescriptorsToImport(file)
val directives = file.importDirectives
val explicitlyImportedFqNames = directives
.asSequence()
.mapNotNull { it.importPath }
.filter { !it.isAllUnder && !it.hasAlias() }
.map { it.fqName }
.toSet()
val fqNames = HashSet<FqName>()
val parentFqNames = HashSet<FqName>()
for (descriptor in optimizerData.descriptorsToImport) {
val fqName = descriptor.importableFqName!!
fqNames.add(fqName)
if (fqName !in explicitlyImportedFqNames) { // we don't add parents of explicitly imported fq-names because such imports are not needed
val parentFqName = fqName.parent()
if (!parentFqName.isRoot) {
parentFqNames.add(parentFqName)
}
}
}
val importPaths = HashSet<ImportPath>(directives.size)
val unusedImports = ArrayList<KtImportDirective>()
for (directive in directives) {
val importPath = directive.importPath ?: continue
if (importPath.alias != null) continue // highlighting of unused alias imports not supported yet
val isUsed = if (!importPaths.add(importPath)) {
false
}
else if (importPath.isAllUnder) {
importPath.fqName in parentFqNames
}
else {
importPath.fqName in fqNames
}
if (!isUsed) {
if (directive.targetDescriptors().isEmpty()) continue // do not highlight unresolved imports as unused
unusedImports += directive
}
}
return ImportData(unusedImports, optimizerData)
}
}
override fun runForWholeFile() = true
override fun checkFile(file: PsiFile, manager: InspectionManager, isOnTheFly: Boolean): Array<out ProblemDescriptor>? {
if (file !is KtFile || file is KtCodeFragment) return null
if (!file.manager.isInProject(file)) return null
if (file.importDirectives.isEmpty()) return null
if (file !is KtFile) return null
val data = analyzeImports(file) ?: return null
val data = KotlinImportOptimizer.collectDescriptorsToImport(file)
val directives = file.importDirectives
val explicitlyImportedFqNames = directives
.asSequence()
.mapNotNull { it.importPath }
.filter { !it.isAllUnder && !it.hasAlias() }
.map { it.fqName }
.toSet()
val fqNames = HashSet<FqName>()
val parentFqNames = HashSet<FqName>()
for (descriptor in data.descriptorsToImport) {
val fqName = descriptor.importableFqName!!
fqNames.add(fqName)
if (fqName !in explicitlyImportedFqNames) { // we don't add parents of explicitly imported fq-names because such imports are not needed
val parentFqName = fqName.parent()
if (!parentFqName.isRoot) {
parentFqNames.add(parentFqName)
}
}
}
val problems = ArrayList<ProblemDescriptor>()
val importPaths = HashSet<ImportPath>(directives.size)
for (directive in directives) {
val importPath = directive.importPath ?: continue
if (importPath.alias != null) continue // highlighting of unused alias imports not supported yet
val isUsed = if (!importPaths.add(importPath)) {
false
}
else if (importPath.isAllUnder) {
importPath.fqName in parentFqNames
}
else {
importPath.fqName in fqNames
}
if (!isUsed) {
if (directive.targetDescriptors().isEmpty()) continue // do not highlight unresolved imports as unused
val fixes = arrayListOf<LocalQuickFix>()
fixes.add(OptimizeImportsQuickFix(file))
if (!CodeInsightSettings.getInstance().OPTIMIZE_IMPORTS_ON_THE_FLY) {
fixes.add(EnableOptimizeImportsOnTheFlyFix(file))
}
problems.add(manager.createProblemDescriptor(directive,
"Unused import directive",
isOnTheFly,
fixes.toTypedArray(),
ProblemHighlightType.LIKE_UNUSED_SYMBOL))
val problems = data.unusedImports.map {
val fixes = arrayListOf<LocalQuickFix>()
fixes.add(OptimizeImportsQuickFix(file))
if (!CodeInsightSettings.getInstance().OPTIMIZE_IMPORTS_ON_THE_FLY) {
fixes.add(EnableOptimizeImportsOnTheFlyFix(file))
}
manager.createProblemDescriptor(it,
"Unused import directive",
isOnTheFly,
fixes.toTypedArray(),
ProblemHighlightType.LIKE_UNUSED_SYMBOL)
}
if (isOnTheFly) {
scheduleOptimizeImportsOnTheFly(file, data)
scheduleOptimizeImportsOnTheFly(file, data.optimizerData)
}
return problems.toTypedArray()

View File

@@ -67,6 +67,8 @@ import org.jetbrains.kotlin.resolve.descriptorUtil.getSuperClassNotAny
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
import org.jetbrains.kotlin.resolve.scopes.utils.findClassifier
import java.util.*
import kotlin.collections.LinkedHashMap
import kotlin.collections.LinkedHashSet
data class ExtractSuperInfo(
val originalClass: KtClassOrObject,
@@ -164,7 +166,7 @@ class ExtractSuperRefactoring(
}
}
}
conflictChecker.checkAllConflicts(usages, conflicts)
conflictChecker.checkAllConflicts(usages, LinkedHashSet<UsageInfo>(), conflicts)
if (targetParent is PsiDirectory) {
ExtractSuperClassUtil.checkSuperAccessible(targetParent, conflicts, originalClass.toLightClass())
}

View File

@@ -57,7 +57,7 @@ class KotlinChangePackageRefactoring(val file: KtFile) {
override fun verify(file: PsiFile) = null
},
delegate = MoveDeclarationsDelegate.TopLevel,
updateInternalReferences = false
scanEntireFile = false
),
Mover.Idle // we don't need to move any declarations physically
)

View File

@@ -99,7 +99,6 @@ class MoveDeclarationToSeparateFileIntention :
delegate = MoveDeclarationsDelegate.TopLevel,
searchInCommentsAndStrings = false,
searchInNonCode = false,
updateInternalReferences = true,
moveCallback = MoveCallback {
val newFile = directory.findFile(targetFileName) as KtFile
val newDeclaration = newFile.declarations.first()

View File

@@ -37,11 +37,11 @@ sealed class MoveDeclarationsDelegate {
abstract fun findUsages(descriptor: MoveDeclarationsDescriptor): List<UsageInfo>
abstract fun collectConflicts(
descriptor: MoveDeclarationsDescriptor,
usages: MutableList<UsageInfo>,
internalUsages: MutableSet<UsageInfo>,
conflicts: MultiMap<PsiElement, String>
)
abstract fun preprocessDeclaration(descriptor: MoveDeclarationsDescriptor, originalDeclaration: KtNamedDeclaration)
abstract fun preprocessUsages(project: Project, usages: List<UsageInfo>)
abstract fun preprocessUsages(project: Project, descriptor: MoveDeclarationsDescriptor, usages: List<UsageInfo>)
object TopLevel : MoveDeclarationsDelegate() {
override fun getContainerChangeInfo(originalDeclaration: KtNamedDeclaration, moveTarget: KotlinMoveTarget): ContainerChangeInfo {
@@ -53,7 +53,7 @@ sealed class MoveDeclarationsDelegate {
override fun collectConflicts(
descriptor: MoveDeclarationsDescriptor,
usages: MutableList<UsageInfo>,
internalUsages: MutableSet<UsageInfo>,
conflicts: MultiMap<PsiElement, String>
) {
@@ -63,7 +63,7 @@ sealed class MoveDeclarationsDelegate {
}
override fun preprocessUsages(project: Project, usages: List<UsageInfo>) {
override fun preprocessUsages(project: Project, descriptor: MoveDeclarationsDescriptor, usages: List<UsageInfo>) {
}
}
@@ -90,10 +90,10 @@ sealed class MoveDeclarationsDelegate {
override fun collectConflicts(
descriptor: MoveDeclarationsDescriptor,
usages: MutableList<UsageInfo>,
internalUsages: MutableSet<UsageInfo>,
conflicts: MultiMap<PsiElement, String>
) {
val usageIterator = usages.iterator()
val usageIterator = internalUsages.iterator()
while (usageIterator.hasNext()) {
val usage = usageIterator.next()
val element = usage.element ?: continue
@@ -136,19 +136,24 @@ sealed class MoveDeclarationsDelegate {
}
}
override fun preprocessUsages(project: Project, usages: List<UsageInfo>) {
override fun preprocessUsages(project: Project, descriptor: MoveDeclarationsDescriptor, usages: List<UsageInfo>) {
if (outerInstanceParameterName == null) return
val psiFactory = KtPsiFactory(project)
val newOuterInstanceRef = psiFactory.createExpression(outerInstanceParameterName)
val classToMove = descriptor.elementsToMove.singleOrNull() as? KtClass
for (usage in usages) {
val referencedNestedClass = (usage as? MoveRenameUsageInfo)?.referencedElement?.unwrapped as? KtClassOrObject
val outerClass = referencedNestedClass?.containingClassOrObject
val lightOuterClass = outerClass?.toLightClass()
if (lightOuterClass != null) {
MoveInnerClassUsagesHandler.EP_NAME
.forLanguage(usage.element!!.language)
?.correctInnerClassUsage(usage, lightOuterClass)
if (usage is MoveRenameUsageInfo) {
val referencedNestedClass = usage.referencedElement?.unwrapped as? KtClassOrObject
if (referencedNestedClass == classToMove) {
val outerClass = referencedNestedClass?.containingClassOrObject
val lightOuterClass = outerClass?.toLightClass()
if (lightOuterClass != null) {
MoveInnerClassUsagesHandler.EP_NAME
.forLanguage(usage.element!!.language)
?.correctInnerClassUsage(usage, lightOuterClass)
}
}
}
when (usage) {

View File

@@ -32,7 +32,7 @@ import org.jetbrains.kotlin.psi.KtFile
class MoveFilesWithDeclarationsProcessor(
project: Project,
private val sourceFiles: List<KtFile>,
targetDirectory: PsiDirectory,
private val targetDirectory: PsiDirectory,
private val targetFileName: String?,
searchInComments: Boolean,
searchInNonJavaFiles: Boolean,
@@ -43,25 +43,8 @@ class MoveFilesWithDeclarationsProcessor(
true,
searchInComments,
searchInNonJavaFiles,
MoveCallbackImpl(sourceFiles, targetFileName, moveCallback),
moveCallback,
EmptyRunnable.INSTANCE) {
class MoveCallbackImpl(
private val sourceFiles: List<KtFile>,
private val targetFileName: String?,
private val nextCallback: MoveCallback?
) : MoveCallback {
override fun refactoringCompleted() {
try {
if (targetFileName != null) {
sourceFiles.single().name = targetFileName
}
}
finally {
nextCallback?.refactoringCompleted()
}
}
}
override fun getCommandName(): String {
return if (targetFileName != null) "Move " + sourceFiles.single().name else "Move"
}
@@ -69,32 +52,43 @@ class MoveFilesWithDeclarationsProcessor(
override fun preprocessUsages(refUsages: Ref<Array<UsageInfo>>): Boolean {
val usages = refUsages.get()
val distinctConflictUsages = UsageViewUtil.removeDuplicatedUsages(usages.filterIsInstance<ConflictUsageInfo>().toTypedArray())
val (conflictUsages, usagesToProcess) = usages.partition { it is ConflictUsageInfo }
val distinctConflictUsages = UsageViewUtil.removeDuplicatedUsages(conflictUsages.toTypedArray())
val conflicts = MultiMap<PsiElement, String>()
for (conflictUsage in distinctConflictUsages) {
conflicts.putValues(conflictUsage.element, (conflictUsage as ConflictUsageInfo).messages)
}
refUsages.set(usagesToProcess.toTypedArray())
return showConflicts(conflicts, usages)
}
// Assign a temporary name to file-under-move to avoid naming conflict during the refactoring
private fun renameFileTemporarily() {
if (targetFileName != null) {
val sourceFile = sourceFiles.single()
//noinspection ConstantConditions
val temporaryName = UniqueNameGenerator.generateUniqueName(
"temp",
"",
".kt",
sourceFile.containingDirectory!!.files.map { file -> file.name })
sourceFile.name = temporaryName
if (targetFileName == null || targetDirectory.findFile(targetFileName) == null) return
val sourceFile = sourceFiles.single()
val temporaryName = UniqueNameGenerator.generateUniqueName("temp", "", ".kt") {
sourceFile.containingDirectory!!.findFile(it) == null
}
sourceFile.name = temporaryName
}
override fun performRefactoring(usages: Array<UsageInfo>) {
renameFileTemporarily()
val needTemporaryRename = targetFileName != null && targetDirectory.findFile(targetFileName) != null
if (needTemporaryRename) {
renameFileTemporarily()
}
super.performRefactoring(usages)
try {
super.performRefactoring(usages)
}
finally {
if (needTemporaryRename) {
sourceFiles.single().name = targetFileName!!
}
}
}
}

View File

@@ -46,7 +46,11 @@ class MoveKotlinDeclarationsHandler : MoveHandlerDelegate() {
private fun getUniqueContainer(elements: Array<out PsiElement>): PsiElement? {
val getContainer: (PsiElement) -> PsiElement? =
if (elements.any { it.parent !is KtFile }) { e ->
(e as? KtNamedDeclaration)?.containingClassOrObject
when (e) {
is KtNamedDeclaration -> e.containingClassOrObject
is KtFile -> e.parent
else -> null
}
}
else { e ->
e.containingFile?.parent
@@ -69,7 +73,13 @@ class MoveKotlinDeclarationsHandler : MoveHandlerDelegate() {
return false
}
val elementsToSearch = elements.mapTo(LinkedHashSet()) { it as KtNamedDeclaration }
val elementsToSearch = elements.flatMapTo(LinkedHashSet<KtNamedDeclaration>()) {
when (it) {
is KtNamedDeclaration -> listOf(it)
is KtFile -> it.declarations.filterIsInstance<KtNamedDeclaration>()
else -> emptyList()
}
}
// todo: allow moving companion object
if (elementsToSearch.any { it is KtObjectDeclaration && it.isCompanion() }) {
@@ -142,10 +152,14 @@ class MoveKotlinDeclarationsHandler : MoveHandlerDelegate() {
}
return elements.all { e ->
if (e is KtClass || (e is KtObjectDeclaration && !e.isObjectLiteral()) || e is KtNamedFunction || e is KtProperty) {
(editorMode || (e as KtNamedDeclaration).canMove()) && e.canRefactor()
when {
e is KtClass || e is KtObjectDeclaration && !e.isObjectLiteral() || e is KtNamedFunction || e is KtProperty ->
(editorMode || (e as KtNamedDeclaration).canMove()) && e.canRefactor()
e is KtFile ->
e.declarations.any { it is KtNamedDeclaration } && e.canRefactor()
else ->
false
}
else false
}
}

View File

@@ -37,21 +37,16 @@ import com.intellij.usageView.UsageViewBundle
import com.intellij.usageView.UsageViewDescriptor
import com.intellij.usageView.UsageViewUtil
import com.intellij.util.IncorrectOperationException
import com.intellij.util.SmartList
import com.intellij.util.containers.MultiMap
import gnu.trove.THashMap
import gnu.trove.TObjectHashingStrategy
import org.jetbrains.kotlin.asJava.elements.KtLightElement
import org.jetbrains.kotlin.asJava.toLightElements
import org.jetbrains.kotlin.descriptors.DeclarationDescriptorWithSource
import org.jetbrains.kotlin.idea.codeInsight.shorten.addToShorteningWaitSet
import org.jetbrains.kotlin.idea.core.deleteSingle
import org.jetbrains.kotlin.idea.refactoring.fqName.getKotlinFqName
import org.jetbrains.kotlin.idea.refactoring.move.UnqualifiableMoveRenameUsageInfo
import org.jetbrains.kotlin.idea.refactoring.move.createMoveUsageInfoIfPossible
import org.jetbrains.kotlin.idea.refactoring.move.getInternalReferencesToUpdateOnPackageNameChange
import org.jetbrains.kotlin.idea.refactoring.move.*
import org.jetbrains.kotlin.idea.refactoring.move.moveFilesOrDirectories.MoveKotlinClassHandler
import org.jetbrains.kotlin.idea.refactoring.move.postProcessMoveUsages
import org.jetbrains.kotlin.idea.references.KtSimpleNameReference.ShorteningMode
import org.jetbrains.kotlin.idea.search.projectScope
import org.jetbrains.kotlin.psi.*
@@ -92,7 +87,7 @@ class MoveDeclarationsDescriptor(
val delegate: MoveDeclarationsDelegate,
val searchInCommentsAndStrings: Boolean = true,
val searchInNonCode: Boolean = true,
val updateInternalReferences: Boolean = true,
val scanEntireFile: Boolean = false,
val deleteSourceFiles: Boolean = false,
val moveCallback: MoveCallback? = null,
val openInEditor: Boolean = false
@@ -125,10 +120,13 @@ class MoveKotlinDeclarationsProcessor(
return MoveMultipleElementsViewDescriptor(elementsToMove.toTypedArray(), targetContainerFqName)
}
private val usagesToProcessBeforeMove = SmartList<UsageInfo>()
fun getConflictsAsUsages(): List<UsageInfo> = conflicts.entrySet().map { ConflictUsageInfo(it.key, it.value) }
class UsagesToProcessBeforeMoveWrapper(
sourceFile: KtFile,
val usages: Collection<UsageInfo>
): UsageInfo(sourceFile)
public override fun findUsages(): Array<UsageInfo> {
if (elementsToMove.isEmpty()) return UsageInfo.EMPTY_ARRAY
@@ -144,7 +142,7 @@ class MoveKotlinDeclarationsProcessor(
.search(lightElement, projectScope, false)
.mapNotNullTo(ArrayList()) { ref ->
if (foundReferences.add(ref) && elementsToMove.all { !it.isAncestor(ref.element)}) {
createMoveUsageInfoIfPossible(ref, lightElement, true)
createMoveUsageInfoIfPossible(ref, lightElement, true, null)
}
else null
}
@@ -169,24 +167,38 @@ class MoveKotlinDeclarationsProcessor(
}
}
val usagesToProcessBeforeMove = LinkedHashSet<UsageInfo>()
val usages = ArrayList<UsageInfo>()
val conflictChecker = MoveConflictChecker(project, elementsToMove, descriptor.moveTarget, elementsToMove.first())
for (kotlinToLightElements in kotlinToLightElementsBySourceFile.values) {
kotlinToLightElements.keys.forEach {
if (descriptor.updateInternalReferences) {
for ((sourceFile, kotlinToLightElements) in kotlinToLightElementsBySourceFile) {
val internalUsages = LinkedHashSet<UsageInfo>()
val externalUsages = ArrayList<UsageInfo>()
if (descriptor.scanEntireFile) {
val changeInfo = ContainerChangeInfo(
ContainerInfo.Package(sourceFile.packageFqName),
descriptor.moveTarget.targetContainerFqName?.let { ContainerInfo.Package(it) } ?: ContainerInfo.UnknownPackage
)
internalUsages += sourceFile.getInternalReferencesToUpdateOnPackageNameChange(changeInfo)
}
else {
kotlinToLightElements.keys.forEach {
val packageNameInfo = descriptor.delegate.getContainerChangeInfo(it, descriptor.moveTarget)
val (usagesToProcessLater, usagesToProcessEarly) = it
.getInternalReferencesToUpdateOnPackageNameChange(packageNameInfo)
.partition { it is UnqualifiableMoveRenameUsageInfo }
usages.addAll(usagesToProcessLater)
usagesToProcessBeforeMove.addAll(usagesToProcessEarly)
internalUsages += it.getInternalReferencesToUpdateOnPackageNameChange(packageNameInfo)
}
}
usages += descriptor.delegate.findUsages(descriptor)
collectUsages(kotlinToLightElements, usages)
conflictChecker.checkAllConflicts(usages, conflicts)
descriptor.delegate.collectConflicts(descriptor, usages, conflicts)
internalUsages += descriptor.delegate.findUsages(descriptor)
collectUsages(kotlinToLightElements, externalUsages)
conflictChecker.checkAllConflicts(externalUsages, internalUsages, conflicts)
descriptor.delegate.collectConflicts(descriptor, internalUsages, conflicts)
usages += externalUsages
val (usagesToProcessLater, usagesToProcessEarly) = internalUsages.partition { it is UnqualifiableMoveRenameUsageInfo }
usages += usagesToProcessLater
usagesToProcessBeforeMove += usagesToProcessEarly
usages += UsagesToProcessBeforeMoveWrapper(sourceFile, usagesToProcessBeforeMove)
}
descriptor.delegate.collectConflicts(descriptor, usagesToProcessBeforeMove, conflicts)
@@ -217,7 +229,12 @@ class MoveKotlinDeclarationsProcessor(
try {
val usageList = usages.toList()
descriptor.delegate.preprocessUsages(project, usageList)
val (usagesToProcessBeforeMoveWrappers, usagesToProcessAfterMove) =
usageList.partition { it is UsagesToProcessBeforeMoveWrapper }
val usagesToProcessBeforeMove = usagesToProcessBeforeMoveWrappers.flatMap { (it as UsagesToProcessBeforeMoveWrapper).usages }
descriptor.delegate.preprocessUsages(project, descriptor, usagesToProcessBeforeMove)
descriptor.delegate.preprocessUsages(project, descriptor, usagesToProcessAfterMove)
postProcessMoveUsages(usagesToProcessBeforeMove, shorteningMode = ShorteningMode.NO_SHORTENING)
@@ -243,6 +260,8 @@ class MoveKotlinDeclarationsProcessor(
)
for ((sourceFile, kotlinToLightElements) in kotlinToLightElementsBySourceFile) {
for ((oldDeclaration, oldLightElements) in kotlinToLightElements) {
val elementListener = transaction!!.getElementListener(oldDeclaration)
val newDeclaration = moveDeclaration(oldDeclaration, descriptor.moveTarget)
if (newDeclaration == null) {
for (oldElement in oldLightElements) {
@@ -253,7 +272,7 @@ class MoveKotlinDeclarationsProcessor(
oldToNewElementsMapping[sourceFile] = newDeclaration.containingKtFile
transaction!!.getElementListener(oldDeclaration).elementMoved(newDeclaration)
elementListener.elementMoved(newDeclaration)
for ((oldElement, newElement) in oldLightElements.asSequence().zip(newDeclaration.toLightElements().asSequence())) {
oldToNewElementsMapping[oldElement] = newElement
}
@@ -268,7 +287,7 @@ class MoveKotlinDeclarationsProcessor(
}
}
nonCodeUsages = postProcessMoveUsages(usageList, oldToNewElementsMapping).toTypedArray()
nonCodeUsages = postProcessMoveUsages(usagesToProcessAfterMove, oldToNewElementsMapping).toTypedArray()
}
catch (e: IncorrectOperationException) {
nonCodeUsages = null
@@ -286,8 +305,4 @@ class MoveKotlinDeclarationsProcessor(
}
override fun getCommandName(): String = REFACTORING_NAME
}
interface D : DeclarationDescriptorWithSource {
}

View File

@@ -23,6 +23,7 @@ import com.intellij.psi.PsiElement
import com.intellij.psi.PsiMember
import com.intellij.psi.PsiMethod
import com.intellij.psi.search.GlobalSearchScope
import com.intellij.psi.search.searches.ReferencesSearch
import com.intellij.refactoring.RefactoringBundle
import com.intellij.refactoring.util.*
import com.intellij.usageView.UsageInfo
@@ -35,15 +36,16 @@ import org.jetbrains.kotlin.descriptors.impl.MutablePackageFragmentDescriptor
import org.jetbrains.kotlin.idea.caches.resolve.*
import org.jetbrains.kotlin.idea.codeInsight.DescriptorToSourceUtilsIde
import org.jetbrains.kotlin.idea.refactoring.getUsageContext
import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.contains
import org.jetbrains.kotlin.psi.psiUtil.forEachDescendantOfType
import org.jetbrains.kotlin.psi.psiUtil.getStrictParentOfType
import org.jetbrains.kotlin.psi.psiUtil.isInsideOf
import org.jetbrains.kotlin.psi.psiUtil.*
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.DescriptorUtils
import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
import org.jetbrains.kotlin.resolve.scopes.receivers.ExpressionReceiver
import org.jetbrains.kotlin.resolve.source.KotlinSourceElement
import org.jetbrains.kotlin.resolve.source.getPsi
import org.jetbrains.kotlin.utils.SmartSet
import java.util.*
@@ -83,13 +85,13 @@ class MoveConflictChecker(
is KotlinDirectoryBasedMoveTarget -> {
val packageFqName = targetContainerFqName ?: return null
val targetDir = directory
val targetDir = directory?.virtualFile ?: targetFile
val targetModuleDescriptor = if (targetDir != null) {
val targetModule = ModuleUtilCore.findModuleForPsiElement(targetDir) ?: return null
val targetModule = ModuleUtilCore.findModuleForFile(targetDir, project) ?: return null
val moduleFileIndex = ModuleRootManager.getInstance(targetModule).fileIndex
val targetModuleInfo = when {
moduleFileIndex.isInSourceContent(targetDir.virtualFile) -> targetModule.productionSourceInfo()
moduleFileIndex.isInTestSourceContent(targetDir.virtualFile) -> targetModule.testSourceInfo()
moduleFileIndex.isInSourceContent(targetDir) -> targetModule.productionSourceInfo()
moduleFileIndex.isInTestSourceContent(targetDir) -> targetModule.testSourceInfo()
else -> return null
}
resolutionFacade.findModuleDescriptor(targetModuleInfo) ?: return null
@@ -145,10 +147,14 @@ class MoveConflictChecker(
RefactoringConflictsUtil.analyzeModuleConflicts(project, elementsToMove, usages.toTypedArray(), sourceRoot, conflicts)
}
fun checkModuleConflictsInDeclarations(conflicts: MultiMap<PsiElement, String>) {
private fun checkModuleConflictsInDeclarations(
internalUsages: MutableSet<UsageInfo>,
conflicts: MultiMap<PsiElement, String>
) {
val sourceRoot = moveTarget.targetFile ?: return
val targetModule = ModuleUtilCore.findModuleForFile(sourceRoot, project) ?: return
val resolveScope = GlobalSearchScope.moduleWithDependenciesAndLibrariesScope(targetModule)
val referencesToSkip = HashSet<KtReferenceExpression>()
for (declaration in elementsToMove - doNotGoIn) {
declaration.forEachDescendantOfType<KtReferenceExpression> { refExpr ->
val targetDescriptor = refExpr.analyze(BodyResolveMode.PARTIAL)[BindingContext.REFERENCE_TARGET, refExpr] ?: return@forEachDescendantOfType
@@ -172,8 +178,10 @@ class MoveConflictChecker(
scopeDescription,
CommonRefactoringUtil.htmlEmphasize(targetModule.name))
conflicts.putValue(target, CommonRefactoringUtil.capitalize(message))
referencesToSkip += refExpr
}
}
internalUsages.removeIf { it.reference?.element?.let { it in referencesToSkip } ?: false }
}
fun checkVisibilityInUsages(usages: List<UsageInfo>, conflicts: MultiMap<PsiElement, String>) {
@@ -205,7 +213,7 @@ class MoveConflictChecker(
}
}
fun checkVisibilityInDeclarations(conflicts: MultiMap<PsiElement, String>) {
private fun checkVisibilityInDeclarations(conflicts: MultiMap<PsiElement, String>) {
val targetContainer = moveTarget.getContainerDescriptor() ?: return
for (declaration in elementsToMove - doNotGoIn) {
declaration.forEachDescendantOfType<KtReferenceExpression> { refExpr ->
@@ -218,6 +226,15 @@ class MoveConflictChecker(
is PsiMember -> target.getJavaMemberDescriptor()
else -> null
} ?: return@forEach
if (targetDescriptor is CallableMemberDescriptor &&
targetDescriptor.visibility.normalize() == Visibilities.PROTECTED) {
val resolvedCall = refExpr.getResolvedCall(refExpr.analyze(BodyResolveMode.PARTIAL)) ?: return@forEach
val dispatchReceiver = resolvedCall.dispatchReceiver
if (dispatchReceiver is ExpressionReceiver && dispatchReceiver.expression is KtSuperExpression) return@forEach
val receiverClass = resolvedCall.dispatchReceiver?.type?.constructor?.declarationDescriptor?.source?.getPsi()
if (receiverClass != null && receiverClass.isInsideOf(elementsToMove)) return@forEach
}
if (!targetDescriptor.isVisibleIn(targetContainer)) {
val message = "${render(declaration)} uses ${render(target)} which will be inaccessible after move"
conflicts.putValue(refExpr, message.capitalize())
@@ -227,10 +244,44 @@ class MoveConflictChecker(
}
}
fun checkAllConflicts(usages: List<UsageInfo>, conflicts: MultiMap<PsiElement, String>) {
checkModuleConflictsInUsages(usages, conflicts)
checkModuleConflictsInDeclarations(conflicts)
checkVisibilityInUsages(usages, conflicts)
private fun isToBeMoved(element: PsiElement): Boolean = elementsToMove.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 membersToCheck = LinkedHashSet<KtDeclaration>()
val memberCollector = object : KtVisitorVoid() {
override fun visitClassOrObject(classOrObject: KtClassOrObject) {
val declarations = classOrObject.declarations
declarations.filterTo(membersToCheck) { it.hasModifier(KtTokens.INTERNAL_KEYWORD) }
declarations.forEach { it.accept(this) }
}
}
elementsToMove.forEach { it.accept(memberCollector) }
for (memberToCheck in membersToCheck) {
for (reference in ReferencesSearch.search(memberToCheck)) {
val element = reference.element ?: continue
val usageModule = ModuleUtilCore.findModuleForPsiElement(element)
if (usageModule != targetModule && !isToBeMoved(element)) {
val container = element.getUsageContext()
val message = "${render(container)} uses internal ${render(memberToCheck)} which will be inaccessible after move"
conflicts.putValue(element, message.capitalize())
}
}
}
}
fun checkAllConflicts(
externalUsages: List<UsageInfo>,
internalUsages: MutableSet<UsageInfo>,
conflicts: MultiMap<PsiElement, String>
) {
checkModuleConflictsInUsages(externalUsages, conflicts)
checkModuleConflictsInDeclarations(internalUsages, conflicts)
checkVisibilityInUsages(externalUsages, conflicts)
checkVisibilityInDeclarations(conflicts)
checkInternalMemberUsages(conflicts)
}
}

View File

@@ -90,7 +90,11 @@ class KotlinMoveDirectoryWithClassesHelper : MoveDirectoryWithClassesHelper() {
moveContextMap[file] = MoveContext(moveDestination,
fileHandler.findInternalUsages(file, moveDestination),
moveDeclarationsProcessor)
moveDestination.getPackage()?.let { newPackage -> file.packageDirective?.fqName = FqName(newPackage.qualifiedName).quoteIfNeeded() }
if (moveDeclarationsProcessor != null) {
moveDestination.getPackage()?.let { newPackage ->
file.packageDirective?.fqName = FqName(newPackage.qualifiedName).quoteIfNeeded()
}
}
return true
}
@@ -109,10 +113,12 @@ class KotlinMoveDirectoryWithClassesHelper : MoveDirectoryWithClassesHelper() {
val moveContext = fileToMoveContext[file] ?: return@body
MoveFilesOrDirectoriesUtil.doMoveFile(file, moveContext.newParent)
val moveDeclarationsProcessor = moveContext.moveDeclarationsProcessor ?: return@body
val movedFile = moveContext.newParent.findFile(file.name) ?: return@body
usagesToProcessAfterMove +=
FileUsagesWrapper(movedFile, it.usages + moveContext.internalUsages, moveContext.moveDeclarationsProcessor)
FileUsagesWrapper(movedFile, it.usages + moveContext.internalUsages, moveDeclarationsProcessor)
}
usagesToProcessAfterMove.forEach { fileHandler.retargetUsages(it.usages, it.moveDeclarationsProcessor!!) }
}

View File

@@ -91,7 +91,7 @@ class MoveKotlinFileHandler : MoveFileHandler() {
elementsToMove = psiFile.declarations.filterIsInstance<KtNamedDeclaration>(),
moveTarget = moveTarget,
delegate = MoveDeclarationsDelegate.TopLevel,
updateInternalReferences = false
scanEntireFile = true
),
Mover.Idle
)
@@ -122,7 +122,6 @@ class MoveKotlinFileHandler : MoveFileHandler() {
usages += it.findUsages()
usages += it.getConflictsAsUsages()
}
newParent?.let { usages += findInternalUsages(psiFile, it) }
return usages
}

View File

@@ -42,6 +42,7 @@ import org.jetbrains.kotlin.asJava.unwrapped
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.idea.KotlinFileType
import org.jetbrains.kotlin.idea.caches.resolve.analyzeFully
import org.jetbrains.kotlin.idea.caches.resolve.getJavaMemberDescriptor
import org.jetbrains.kotlin.idea.caches.resolve.resolveToDescriptor
import org.jetbrains.kotlin.idea.codeInsight.DescriptorToSourceUtilsIde
import org.jetbrains.kotlin.idea.codeInsight.KotlinFileReferencesResolver
@@ -121,8 +122,10 @@ fun KtElement.lazilyProcessInternalReferencesToUpdateOnPackageNameChange(
fun processReference(refExpr: KtSimpleNameExpression, bindingContext: BindingContext): ((KtSimpleNameExpression) -> UsageInfo?)? {
val descriptor = bindingContext[BindingContext.REFERENCE_TARGET, refExpr]?.getImportableDescriptor() ?: return null
val containingDescriptor = descriptor.containingDeclaration ?: return null
val declaration = DescriptorToSourceUtilsIde.getAnyDeclaration(project, descriptor) ?: return null
val containingDeclaration = DescriptorToSourceUtilsIde.getAnyDeclaration(project, containingDescriptor) as? KtClassOrObject
// Special case for enum entry superclass references (they have empty text and don't need to be processed by the refactoring)
if (refExpr.textRange.isEmpty) return null
@@ -134,7 +137,6 @@ fun KtElement.lazilyProcessInternalReferencesToUpdateOnPackageNameChange(
val isCallableReference = isCallableReference(refExpr.mainReference)
if (isCallable && !isCallableReference) {
val containingDescriptor = descriptor.containingDeclaration
if (isExtension && containingDescriptor is ClassDescriptor) {
val implicitClass = (refExpr.getResolvedCall(bindingContext)?.dispatchReceiver as? ImplicitClassReceiver)?.classDescriptor
if (DescriptorUtils.isCompanionObject(implicitClass)) {
@@ -174,7 +176,8 @@ fun KtElement.lazilyProcessInternalReferencesToUpdateOnPackageNameChange(
.firstOrNull()
fun doCreateUsageInfo(refExpr: KtSimpleNameExpression): UsageInfo? {
if (isAncestor(declaration, false)) {
// Check container instead of declaration itself as the latter may be not real (e.g. fake override)
if (isAncestor(containingDeclaration ?: declaration, false)) {
if (descriptor.importableFqName == null) return null
if (isUnqualifiedExtensionReference(refExpr.mainReference, declaration)) return null
if (isCallableReference(refExpr.mainReference)) return null
@@ -183,7 +186,8 @@ fun KtElement.lazilyProcessInternalReferencesToUpdateOnPackageNameChange(
val prefix = containerFqName.asString()
val prefixOffset = it.indexOf(prefix)
val newFqName = if (prefix.isEmpty()) {
FqName("${newContainer.fqName!!.asString()}.$it")
val newContainerFqName = newContainer.fqName!!
FqName(if (newContainerFqName.isRoot) it else "${newContainer.fqName!!.asString()}.$it")
}
else {
FqName(it.replaceRange(prefixOffset..prefixOffset + prefix.length - 1, newContainer.fqName!!.asString()))
@@ -192,7 +196,7 @@ fun KtElement.lazilyProcessInternalReferencesToUpdateOnPackageNameChange(
}
}
return createMoveUsageInfoIfPossible(refExpr.mainReference, declaration, false)
return createMoveUsageInfoIfPossible(refExpr.mainReference, declaration, false, fqName.toSafe())
}
if (isExtension || isCallableReference || containerFqName != null || isImported(descriptor)) return ::doCreateUsageInfo
@@ -226,10 +230,20 @@ class MoveRenameSelfUsageInfo(ref: KtSimpleNameReference, refTarget: PsiElement,
override fun getReference() = super.getReference() as? KtSimpleNameReference
}
class QualifiableMoveRenameUsageInfo(
element: PsiElement,
reference: PsiReference,
startOffset: Int,
endOffset: Int,
referencedElement: PsiElement,
val newFqName: FqName?
): MoveRenameUsageInfo(element, reference, startOffset, endOffset, referencedElement, false)
fun createMoveUsageInfoIfPossible(
reference: PsiReference,
referencedElement: PsiElement,
addImportToOriginalFile: Boolean
addImportToOriginalFile: Boolean,
newFqName: FqName?
): UsageInfo? {
val element = reference.element
if (element.getStrictParentOfType<KtSuperExpression>() != null) return null
@@ -243,7 +257,7 @@ fun createMoveUsageInfoIfPossible(
element, reference, startOffset, endOffset, referencedElement, element.containingFile!!, addImportToOriginalFile
)
}
return MoveRenameUsageInfo(element, reference, startOffset, endOffset, referencedElement, false)
return QualifiableMoveRenameUsageInfo(element, reference, startOffset, endOffset, referencedElement, newFqName)
}
private fun isUnqualifiedExtensionReference(reference: PsiReference, referencedElement: PsiElement): Boolean {
@@ -303,7 +317,7 @@ private fun updateJavaReference(reference: PsiReferenceExpression, oldElement: P
/**
* Perform usage postprocessing and return non-code usages
*/
fun postProcessMoveUsages(usages: List<UsageInfo>,
fun postProcessMoveUsages(usages: Collection<UsageInfo>,
oldToNewElementsMapping: Map<PsiElement, PsiElement> = Collections.emptyMap(),
shorteningMode: ShorteningMode = ShorteningMode.DELAYED_SHORTENING
): List<NonCodeUsageInfo> {
@@ -341,8 +355,13 @@ fun postProcessMoveUsages(usages: List<UsageInfo>,
is UnqualifiableMoveRenameUsageInfo -> {
val file = with(usage) { if (addImportToOriginalFile) originalFile else counterpart(originalFile) } as KtFile
val declaration = counterpart(usage.referencedElement!!).unwrapped as KtDeclaration
ImportInsertHelper.getInstance(usage.project).importDescriptor(file, declaration.resolveToDescriptor())
val declaration = counterpart(usage.referencedElement!!).unwrapped
val referencedDescriptor = when (declaration) {
is KtDeclaration -> declaration.resolveToDescriptor()
is PsiMember -> declaration.getJavaMemberDescriptor()
else -> null
} ?: continue@usageLoop
ImportInsertHelper.getInstance(usage.project).importDescriptor(file, referencedDescriptor)
}
is MoveRenameUsageInfo -> {
@@ -351,7 +370,15 @@ fun postProcessMoveUsages(usages: List<UsageInfo>,
val reference = usage.reference ?: (usage.element as? KtSimpleNameExpression)?.mainReference
try {
when {
reference is KtSimpleNameReference -> reference.bindToElement(newElement, shorteningMode)
reference is KtSimpleNameReference -> {
val newFqName = (usage as? QualifiableMoveRenameUsageInfo)?.newFqName
if (newFqName != null) {
reference.bindToFqName(newFqName, shorteningMode)
}
else {
reference.bindToElement(newElement, shorteningMode)
}
}
reference is PsiReferenceExpression && updateJavaReference(reference, oldElement, newElement) -> continue@usageLoop
else -> reference?.bindToElement(newElement)
}

View File

@@ -0,0 +1,6 @@
class a {
companion object b {
fun c() = "..."
}
fun d() = c()
}

View File

@@ -0,0 +1,10 @@
class <caret>a {
companion object b {
fun c() = "..."
}
fun d() = c()
}
fun foo() {
}

View File

@@ -0,0 +1,4 @@
{
"mainFile": "test.kt",
"intentionClass": "org.jetbrains.kotlin.idea.refactoring.move.moveDeclarations.MoveDeclarationToSeparateFileIntention"
}

View File

@@ -1,8 +1,5 @@
package `in`.foo.`fun`
import `in`.foo.`fun`.Foo
import `in`.foo.`fun`.foo
fun test() {
Foo()
foo()

View File

@@ -1,6 +1,3 @@
import Foo
import foo
fun test() {
Foo()
foo()

View File

@@ -1,8 +1,5 @@
package target
import target.Foo
import target.foo
fun test() {
Foo()
foo()

View File

@@ -1,5 +1,3 @@
import J.bar
fun test() {
J.bar("1")
J.bar("3")

View File

@@ -1,5 +1,3 @@
import A.*
fun bar(s: String) {
val t: B.C.X = B.C.X()
}

View File

@@ -1,5 +1,3 @@
import A.*
fun bar(s: String) {
val t: B.X = B.X()
}

View File

@@ -1,5 +1,3 @@
import A.*
fun bar(s: String) {
val t: B.X = B.X()
}

View File

@@ -1,6 +1,5 @@
package k
import j.A.*
import j.B
fun bar(s: String) {

View File

@@ -1,6 +1,5 @@
package k
import j.A
import j.B
fun bar(s: String) {

View File

@@ -1,7 +1,5 @@
package b
import b.*
fun bar() {
val t: X = X()
}

View File

@@ -1,7 +1,5 @@
package a
import a.A.*
fun bar(s: String) {
val t: X = X()
}

View File

@@ -1,7 +1,5 @@
package a
import a.A.*
fun bar(s: String) {
val t: X = X(A(), "test")
}

View File

@@ -1,7 +1,5 @@
package a
import a.X
fun bar(s: String) {
val t: X = X(A(), "test")
}

View File

@@ -1,7 +1,5 @@
package a
import a.A.*
fun bar(s: String) {
val t: X = X(A()) { s }
}

View File

@@ -1,7 +1,5 @@
package a
import a.X
fun bar(s: String) {
val t: X = X(A()) { s }
}

View File

@@ -1,7 +1,5 @@
package a
import a.A.*
fun bar(s: String) {
val t: Y = Y()
}

View File

@@ -1,7 +1,5 @@
package b
import a.*
fun bar() {
val t: A = A()
}

View File

@@ -1,6 +1,5 @@
package c
import a.*
import b.A
fun bar() {

View File

@@ -1,5 +1,3 @@
import A.*
fun bar(s: String) {
B.C.X = s
}

View File

@@ -1,5 +1,3 @@
import A.*
fun bar(s: String) {
B.X = s
}

View File

@@ -1,5 +1,3 @@
import A.*
fun bar(s: String) {
B.X = s
}

View File

@@ -1,6 +1,5 @@
package k
import j.A.*
import j.B
fun bar(s: String) {

View File

@@ -1,6 +1,5 @@
package k
import j.A
import j.B
fun bar(s: String) {

View File

@@ -1,7 +1,5 @@
package b
import a.*
fun bar() {
val t: A = A()
}

View File

@@ -1,5 +1,3 @@
import A.*
fun bar(s: String) {
B.C.foo(s)
}

View File

@@ -1,5 +1,3 @@
import A.*
fun bar(s: String) {
B.foo(s)
}

View File

@@ -1,5 +1,3 @@
import A.*
fun bar(s: String) {
B.foo(s)
}

View File

@@ -1,6 +1,5 @@
package k
import j.A.*
import j.B
fun bar(s: String) {

View File

@@ -1,6 +1,5 @@
package k
import j.A
import j.B
fun bar(s: String) {

View File

@@ -1,6 +1,3 @@
import Foo
import foo
fun test() {
Foo()
foo()

View File

@@ -1,8 +1,5 @@
package target
import target.Foo
import target.foo
fun test() {
Foo()
foo()

View File

@@ -0,0 +1,14 @@
<?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" />
<sourceFolder url="file://$MODULE_DIR$/r2" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/r1" isTestSource="false" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
<orderEntry type="library" name="KotlinJavaRuntime" level="project" />
</component>
</module>

View File

@@ -0,0 +1,5 @@
package y
fun foo() {
}

View File

@@ -0,0 +1,14 @@
<?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" />
<sourceFolder url="file://$MODULE_DIR$/r2" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/r1" isTestSource="false" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
<orderEntry type="library" name="KotlinJavaRuntime" level="project" />
</component>
</module>

View File

@@ -0,0 +1,5 @@
package y
fun foo() {
}

View File

@@ -0,0 +1,7 @@
{
"mainFile": "A/r1/x/test.kt",
"type": "MOVE_DIRECTORY_WITH_CLASSES",
"sourceDir": "A/r1/x",
"targetDir": "A/r1/z",
"isMultiModule": "true"
}

View File

@@ -1,7 +1,6 @@
package b
import a.f2
import b.f3
import c.f4
fun test() {

View File

@@ -1,6 +1,5 @@
package c
import a.*
import b.TEST
import b.Test
import b.test

View File

@@ -1,7 +1,6 @@
package test2
import test.A
import test.A.B
import test.C
fun foo2(): C {

View File

@@ -1,6 +1,5 @@
package test2
import test.A
import test.C
fun foo(): C {

View File

@@ -1,6 +1,5 @@
package test2
import test.A.B
import test.C
fun foo(): C {

View File

@@ -1,6 +1,5 @@
package test2
import test.A
import test.B
fun foo(): B {

View File

@@ -1,6 +1,5 @@
package test2
import test.A
import test.B
fun foo2(): B {

View File

@@ -1,7 +1,6 @@
package test2
import test.A
import test.A.B
fun foo(): A.C {
return A.C()

View File

@@ -1,7 +1,6 @@
package test2
import test.A
import test.A.B
fun foo(): A.C {
return A.C()

View File

@@ -1,6 +1,5 @@
package test2
import test.A
import test.B
fun foo(): B {

View File

@@ -1,6 +1,5 @@
package test2
import test.A
import test3.D
fun foo(): D.C {

View File

@@ -1,6 +1,5 @@
package test2
import test.A.B
import test3.D
fun foo(): D.C {

View File

@@ -1,6 +1,5 @@
package test2
import test.A
import test.B
fun foo(): B {

View File

@@ -0,0 +1,4 @@
package source
fun test() = J::bar

View File

@@ -0,0 +1,7 @@
package source;
public class J {
public static void bar() {
}
}

View File

@@ -0,0 +1,7 @@
package target
import source.J.bar
class Test {
val x = J::bar
}

View File

@@ -0,0 +1,7 @@
package source
fun test() = J::bar
class <caret>Test {
val x = J::bar
}

View File

@@ -0,0 +1,7 @@
package source;
public class J {
public static void bar() {
}
}

View File

@@ -0,0 +1,5 @@
{
"mainFile": "source/Foo.kt",
"type": "MOVE_KOTLIN_TOP_LEVEL_DECLARATIONS",
"targetPackage": "target"
}

View File

@@ -0,0 +1,13 @@
package source
class Logger {
fun debug(s: () -> String) {
}
}
open class Klogging
val Klogging.loggerExt: Logger get() = Logger
fun Klogging.logExt(s: String) {}

View File

@@ -0,0 +1,14 @@
package target
import source.Klogging
import source.logExt
import source.loggerExt
class Foo {
companion object : Klogging()
fun baz() {
loggerExt.debug { "something" }
logExt("something")
}
}

View File

@@ -0,0 +1,21 @@
package source
class Logger {
fun debug(s: () -> String) {
}
}
open class Klogging
val Klogging.loggerExt: Logger get() = Logger
fun Klogging.logExt(s: String) {}
class <caret>Foo {
companion object : Klogging()
fun baz() {
loggerExt.debug { "something" }
logExt("something")
}
}

View File

@@ -0,0 +1,5 @@
{
"mainFile": "source/Foo.kt",
"type": "MOVE_KOTLIN_TOP_LEVEL_DECLARATIONS",
"targetPackage": "target"
}

View File

@@ -0,0 +1,18 @@
package source
class Logger {
fun debug(s: () -> String) {
}
}
interface ILogging {
val logger: Logger
fun log(s: String)
}
class Klogging : ILogging {
override val logger = Logger()
override fun log(s: String) {}
}

View File

@@ -0,0 +1,13 @@
package target
import source.ILogging
import source.Klogging
class Foo {
companion object : ILogging by Klogging()
fun baz() {
logger.debug { "something" }
log("something")
}
}

View File

@@ -0,0 +1,26 @@
package source
class Logger {
fun debug(s: () -> String) {
}
}
interface ILogging {
val logger: Logger
fun log(s: String)
}
class Klogging : ILogging {
override val logger = Logger()
override fun log(s: String) {}
}
class <caret>Foo {
companion object : ILogging by Klogging()
fun baz() {
logger.debug { "something" }
log("something")
}
}

View File

@@ -0,0 +1,5 @@
{
"mainFile": "source/Foo.kt",
"type": "MOVE_KOTLIN_TOP_LEVEL_DECLARATIONS",
"targetPackage": "target"
}

View File

@@ -0,0 +1,13 @@
package source
class Logger {
fun debug(s: () -> String) {
}
}
open class Klogging {
val logger = Logger()
fun log(s: String) {}
}

View File

@@ -0,0 +1,12 @@
package target
import source.Klogging
class Foo {
companion object : Klogging()
fun baz() {
logger.debug { "something" }
log("something")
}
}

View File

@@ -0,0 +1,21 @@
package source
class Logger {
fun debug(s: () -> String) {
}
}
open class Klogging {
val logger = Logger()
fun log(s: String) {}
}
class <caret>Foo {
companion object : Klogging()
fun baz() {
logger.debug { "something" }
log("something")
}
}

View File

@@ -0,0 +1,5 @@
{
"mainFile": "source/Foo.kt",
"type": "MOVE_KOTLIN_TOP_LEVEL_DECLARATIONS",
"targetPackage": "target"
}

View File

@@ -0,0 +1,8 @@
package source
class Logger {
fun debug(s: () -> String) {
}
}

View File

@@ -0,0 +1,6 @@
package source;
public class Klogging {
public Logger logger = Logger();
public void log(String s) {}
}

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