Refactor common move member methods
(cherry picked from commit 2dd8148)
This commit is contained in:
+17
-50
@@ -16,7 +16,6 @@
|
||||
|
||||
package org.jetbrains.kotlin.idea.intentions
|
||||
|
||||
import com.intellij.openapi.editor.Editor
|
||||
import com.intellij.openapi.util.TextRange
|
||||
import com.intellij.psi.PsiElement
|
||||
import com.intellij.psi.search.searches.ReferencesSearch
|
||||
@@ -25,15 +24,12 @@ import com.intellij.util.containers.MultiMap
|
||||
import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||
import org.jetbrains.kotlin.idea.caches.resolve.analyzeFully
|
||||
import org.jetbrains.kotlin.idea.caches.resolve.unsafeResolveToDescriptor
|
||||
import org.jetbrains.kotlin.idea.caches.resolve.resolveToDescriptorIfAny
|
||||
import org.jetbrains.kotlin.idea.caches.resolve.unsafeResolveToDescriptor
|
||||
import org.jetbrains.kotlin.idea.codeInsight.DescriptorToSourceUtilsIde
|
||||
import org.jetbrains.kotlin.idea.refactoring.checkConflictsInteractively
|
||||
import org.jetbrains.kotlin.idea.refactoring.getUsageContext
|
||||
import org.jetbrains.kotlin.idea.refactoring.move.moveDeclarations.*
|
||||
import org.jetbrains.kotlin.idea.runSynchronouslyWithProgress
|
||||
import org.jetbrains.kotlin.idea.util.application.runReadAction
|
||||
import org.jetbrains.kotlin.idea.util.application.runWriteAction
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
import org.jetbrains.kotlin.psi.psiUtil.containingClassOrObject
|
||||
import org.jetbrains.kotlin.psi.psiUtil.parents
|
||||
@@ -42,47 +38,13 @@ import org.jetbrains.kotlin.resolve.descriptorUtil.isSubclassOf
|
||||
import org.jetbrains.kotlin.resolve.scopes.receivers.ImplicitClassReceiver
|
||||
import org.jetbrains.kotlin.util.findCallableMemberBySignature
|
||||
|
||||
class MoveMemberOutOfCompanionObjectIntention : SelfTargetingRangeIntention<KtNamedDeclaration>(KtNamedDeclaration::class.java,
|
||||
"Move out of companion object") {
|
||||
override fun startInWriteAction() = false
|
||||
|
||||
override fun applicabilityRange(element: KtNamedDeclaration): TextRange? {
|
||||
if (element !is KtNamedFunction && element !is KtProperty && element !is KtClassOrObject) return null
|
||||
val container = element.containingClassOrObject
|
||||
if (!(container is KtObjectDeclaration && container.isCompanion())) return null
|
||||
if (container.containingClassOrObject == null) return null
|
||||
return element.nameIdentifier?.textRange
|
||||
}
|
||||
|
||||
override fun applyTo(element: KtNamedDeclaration, editor: Editor?) {
|
||||
val project = element.project
|
||||
|
||||
val companionObject = element.containingClassOrObject!!
|
||||
val targetClass = companionObject.containingClassOrObject!!
|
||||
|
||||
fun deleteCompanionIfEmpty() {
|
||||
if (companionObject.declarations.isEmpty()) {
|
||||
companionObject.delete()
|
||||
}
|
||||
}
|
||||
|
||||
if (element is KtClassOrObject) {
|
||||
val moveDescriptor = MoveDeclarationsDescriptor(project,
|
||||
listOf(element),
|
||||
KotlinMoveTargetForExistingElement(targetClass),
|
||||
MoveDeclarationsDelegate.NestedClass())
|
||||
runWriteAction {
|
||||
MoveKotlinDeclarationsProcessor(moveDescriptor).run()
|
||||
deleteCompanionIfEmpty()
|
||||
}
|
||||
return
|
||||
}
|
||||
class MoveMemberOutOfCompanionObjectIntention : MoveMemberOutOfObjectIntention("Move out of companion object") {
|
||||
override fun addConflicts(element: KtNamedDeclaration, conflicts: MultiMap<PsiElement, String>) {
|
||||
|
||||
val targetClass = element.containingClassOrObject!!.containingClassOrObject!!
|
||||
val targetClassDescriptor = runReadAction { targetClass.unsafeResolveToDescriptor() as ClassDescriptor }
|
||||
|
||||
val conflicts = MultiMap<PsiElement, String>()
|
||||
|
||||
val refsRequiringClassInstance = project.runSynchronouslyWithProgress("Searching for ${element.name}", true) {
|
||||
val refsRequiringClassInstance = element.project.runSynchronouslyWithProgress("Searching for ${element.name}", true) {
|
||||
runReadAction {
|
||||
ReferencesSearch
|
||||
.search(element)
|
||||
@@ -113,17 +75,22 @@ class MoveMemberOutOfCompanionObjectIntention : SelfTargetingRangeIntention<KtNa
|
||||
runReadAction {
|
||||
val callableDescriptor = element.unsafeResolveToDescriptor() as CallableMemberDescriptor
|
||||
targetClassDescriptor.findCallableMemberBySignature(callableDescriptor)?.let {
|
||||
DescriptorToSourceUtilsIde.getAnyDeclaration(project, it)
|
||||
DescriptorToSourceUtilsIde.getAnyDeclaration(element.project, it)
|
||||
}?.let {
|
||||
conflicts.putValue(it, "Class '${targetClass.name}' already contains ${RefactoringUIUtil.getDescription(it, false)}")
|
||||
}
|
||||
}
|
||||
|
||||
project.checkConflictsInteractively(conflicts) {
|
||||
runWriteAction {
|
||||
Mover.Default(element, targetClass)
|
||||
deleteCompanionIfEmpty()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun getDestination(element: KtNamedDeclaration) = element.containingClassOrObject!!.containingClassOrObject!!
|
||||
|
||||
override fun applicabilityRange(element: KtNamedDeclaration): TextRange? {
|
||||
if (element !is KtNamedFunction && element !is KtProperty && element !is KtClassOrObject) return null
|
||||
val container = element.containingClassOrObject
|
||||
if (!(container is KtObjectDeclaration && container.isCompanion())) return null
|
||||
if (container.containingClassOrObject == null) return null
|
||||
return element.nameIdentifier?.textRange
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
/*
|
||||
* 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.intentions
|
||||
|
||||
import com.intellij.openapi.editor.Editor
|
||||
import com.intellij.openapi.util.TextRange
|
||||
import com.intellij.psi.PsiElement
|
||||
import com.intellij.psi.search.searches.ReferencesSearch
|
||||
import com.intellij.refactoring.util.RefactoringUIUtil
|
||||
import com.intellij.util.containers.MultiMap
|
||||
import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||
import org.jetbrains.kotlin.idea.caches.resolve.analyzeFully
|
||||
import org.jetbrains.kotlin.idea.caches.resolve.resolveToDescriptorIfAny
|
||||
import org.jetbrains.kotlin.idea.caches.resolve.unsafeResolveToDescriptor
|
||||
import org.jetbrains.kotlin.idea.codeInsight.DescriptorToSourceUtilsIde
|
||||
import org.jetbrains.kotlin.idea.refactoring.checkConflictsInteractively
|
||||
import org.jetbrains.kotlin.idea.refactoring.getUsageContext
|
||||
import org.jetbrains.kotlin.idea.refactoring.move.moveDeclarations.*
|
||||
import org.jetbrains.kotlin.idea.runSynchronouslyWithProgress
|
||||
import org.jetbrains.kotlin.idea.util.application.runReadAction
|
||||
import org.jetbrains.kotlin.idea.util.application.runWriteAction
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
import org.jetbrains.kotlin.psi.psiUtil.containingClassOrObject
|
||||
import org.jetbrains.kotlin.psi.psiUtil.parents
|
||||
import org.jetbrains.kotlin.psi.synthetics.findClassDescriptor
|
||||
import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.isSubclassOf
|
||||
import org.jetbrains.kotlin.resolve.scopes.receivers.ImplicitClassReceiver
|
||||
import org.jetbrains.kotlin.util.findCallableMemberBySignature
|
||||
|
||||
abstract class MoveMemberOutOfObjectIntention(text: String) : SelfTargetingRangeIntention<KtNamedDeclaration>(KtNamedDeclaration::class.java, text) {
|
||||
override fun startInWriteAction() = false
|
||||
|
||||
abstract fun getDestination(element: KtNamedDeclaration) : KtElement
|
||||
|
||||
abstract fun addConflicts(element: KtNamedDeclaration,conflicts: MultiMap<PsiElement, String>)
|
||||
|
||||
override fun applyTo(element: KtNamedDeclaration, editor: Editor?) {
|
||||
val project = element.project
|
||||
|
||||
val classOrObject = element.containingClassOrObject!!
|
||||
val destination = getDestination(element)
|
||||
|
||||
fun deleteClassOrObjectIfEmpty() {
|
||||
if (classOrObject.declarations.isEmpty()) {
|
||||
classOrObject.delete()
|
||||
}
|
||||
}
|
||||
|
||||
if (element is KtClassOrObject) {
|
||||
val moveDescriptor = MoveDeclarationsDescriptor(project,
|
||||
listOf(element),
|
||||
KotlinMoveTargetForExistingElement(destination),
|
||||
MoveDeclarationsDelegate.NestedClass())
|
||||
runWriteAction {
|
||||
MoveKotlinDeclarationsProcessor(moveDescriptor).run()
|
||||
deleteClassOrObjectIfEmpty()
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
val conflicts = MultiMap<PsiElement, String>().apply { addConflicts(element, this) }
|
||||
|
||||
project.checkConflictsInteractively(conflicts) {
|
||||
runWriteAction {
|
||||
Mover.Default(element, destination)
|
||||
deleteClassOrObjectIfEmpty()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user