Refactoring & fix warnings
This commit is contained in:
+20
-29
@@ -27,7 +27,6 @@ import com.intellij.psi.PsiNamedElement
|
|||||||
import com.intellij.psi.PsiReference
|
import com.intellij.psi.PsiReference
|
||||||
import com.intellij.psi.search.searches.ReferencesSearch
|
import com.intellij.psi.search.searches.ReferencesSearch
|
||||||
import com.intellij.util.containers.MultiMap
|
import com.intellij.util.containers.MultiMap
|
||||||
import org.jetbrains.kotlin.asJava.namedUnwrappedElement
|
|
||||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||||
import org.jetbrains.kotlin.descriptors.CallableDescriptor
|
import org.jetbrains.kotlin.descriptors.CallableDescriptor
|
||||||
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
||||||
@@ -59,13 +58,14 @@ import org.jetbrains.kotlin.types.isError
|
|||||||
import org.jetbrains.kotlin.types.typeUtil.supertypes
|
import org.jetbrains.kotlin.types.typeUtil.supertypes
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
class ConvertFunctionToPropertyIntention : SelfTargetingIntention<KtNamedFunction>(KtNamedFunction::class.java, "Convert function to property"), LowPriorityAction {
|
class ConvertFunctionToPropertyIntention :
|
||||||
|
SelfTargetingIntention<KtNamedFunction>(KtNamedFunction::class.java, "Convert function to property"), LowPriorityAction {
|
||||||
private var KtNamedFunction.typeFqNameToAdd: String? by UserDataProperty(Key.create("TYPE_FQ_NAME_TO_ADD"))
|
private var KtNamedFunction.typeFqNameToAdd: String? by UserDataProperty(Key.create("TYPE_FQ_NAME_TO_ADD"))
|
||||||
|
|
||||||
private inner class Converter(
|
private inner class Converter(
|
||||||
project: Project,
|
project: Project,
|
||||||
private val editor: Editor?,
|
private val editor: Editor?,
|
||||||
descriptor: FunctionDescriptor
|
descriptor: FunctionDescriptor
|
||||||
) : CallableRefactoring<FunctionDescriptor>(project, descriptor, text) {
|
) : CallableRefactoring<FunctionDescriptor>(project, descriptor, text) {
|
||||||
private val elementsToShorten = ArrayList<KtElement>()
|
private val elementsToShorten = ArrayList<KtElement>()
|
||||||
|
|
||||||
@@ -86,8 +86,7 @@ class ConvertFunctionToPropertyIntention : SelfTargetingIntention<KtNamedFunctio
|
|||||||
|
|
||||||
if (originalFunction.equalsToken != null) {
|
if (originalFunction.equalsToken != null) {
|
||||||
getterExpression(originalFunction.bodyExpression!!.text, breakLine = originalFunction.typeReference != null)
|
getterExpression(originalFunction.bodyExpression!!.text, breakLine = originalFunction.typeReference != null)
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
originalFunction.bodyBlockExpression?.let { body ->
|
originalFunction.bodyBlockExpression?.let { body ->
|
||||||
transform {
|
transform {
|
||||||
append("\nget() ")
|
append("\nget() ")
|
||||||
@@ -121,26 +120,20 @@ class ConvertFunctionToPropertyIntention : SelfTargetingIntention<KtNamedFunctio
|
|||||||
val functionDescriptor = callable.unsafeResolveToDescriptor(BodyResolveMode.PARTIAL) as FunctionDescriptor
|
val functionDescriptor = callable.unsafeResolveToDescriptor(BodyResolveMode.PARTIAL) as FunctionDescriptor
|
||||||
val type = functionDescriptor.returnType
|
val type = functionDescriptor.returnType
|
||||||
val typeToInsert = when {
|
val typeToInsert = when {
|
||||||
type == null || type.isError -> null
|
type == null || type.isError -> null
|
||||||
type.constructor.isDenotable -> type
|
type.constructor.isDenotable -> type
|
||||||
else -> type.supertypes().firstOrNull { it.constructor.isDenotable }
|
else -> type.supertypes().firstOrNull { it.constructor.isDenotable }
|
||||||
} ?: functionDescriptor.builtIns.nullableAnyType
|
} ?: functionDescriptor.builtIns.nullableAnyType
|
||||||
callable.typeFqNameToAdd = IdeDescriptorRenderers.SOURCE_CODE.renderType(typeToInsert)
|
callable.typeFqNameToAdd = IdeDescriptorRenderers.SOURCE_CODE.renderType(typeToInsert)
|
||||||
}
|
}
|
||||||
|
|
||||||
callableDescriptor.getContainingScope()
|
callableDescriptor.getContainingScope()
|
||||||
?.findVariable(callableDescriptor.name, NoLookupLocation.FROM_IDE)
|
?.findVariable(callableDescriptor.name, NoLookupLocation.FROM_IDE)
|
||||||
?.let { DescriptorToSourceUtilsIde.getAnyDeclaration(project, it) }
|
?.let { DescriptorToSourceUtilsIde.getAnyDeclaration(project, it) }
|
||||||
?.let { reportDeclarationConflict(conflicts, it) { "$it already exists" } }
|
?.let { reportDeclarationConflict(conflicts, it) { s -> "$s already exists" } }
|
||||||
}
|
}
|
||||||
|
|
||||||
if (callable is PsiMethod) {
|
if (callable is PsiMethod) callable.checkDeclarationConflict(getterName, conflicts, callables)
|
||||||
callable.containingClass
|
|
||||||
?.findMethodsByName(getterName, true)
|
|
||||||
// as is necessary here: see KT-10386
|
|
||||||
?.firstOrNull { it.parameterList.parametersCount == 0 && !callables.contains(it.namedUnwrappedElement as PsiElement?) }
|
|
||||||
?.let { reportDeclarationConflict(conflicts, it) { "$it already exists" } }
|
|
||||||
}
|
|
||||||
|
|
||||||
val usages = ReferencesSearch.search(callable)
|
val usages = ReferencesSearch.search(callable)
|
||||||
for (usage in usages) {
|
for (usage in usages) {
|
||||||
@@ -150,26 +143,24 @@ class ConvertFunctionToPropertyIntention : SelfTargetingIntention<KtNamedFunctio
|
|||||||
if (callElement != null && expression.getStrictParentOfType<KtCallableReferenceExpression>() == null) {
|
if (callElement != null && expression.getStrictParentOfType<KtCallableReferenceExpression>() == null) {
|
||||||
if (callElement.typeArguments.isNotEmpty()) {
|
if (callElement.typeArguments.isNotEmpty()) {
|
||||||
conflicts.putValue(
|
conflicts.putValue(
|
||||||
callElement,
|
callElement,
|
||||||
"Type arguments will be lost after conversion: ${StringUtil.htmlEmphasize(callElement.text)}"
|
"Type arguments will be lost after conversion: ${StringUtil.htmlEmphasize(callElement.text)}"
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (callElement.valueArguments.isNotEmpty()) {
|
if (callElement.valueArguments.isNotEmpty()) {
|
||||||
conflicts.putValue(
|
conflicts.putValue(
|
||||||
callElement,
|
callElement,
|
||||||
"Call with arguments will be skipped: ${StringUtil.htmlEmphasize(callElement.text)}"
|
"Call with arguments will be skipped: ${StringUtil.htmlEmphasize(callElement.text)}"
|
||||||
)
|
)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
kotlinCalls.add(callElement)
|
kotlinCalls.add(callElement)
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
kotlinRefsToRename.add(usage)
|
kotlinRefsToRename.add(usage)
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
foreignRefs.add(usage)
|
foreignRefs.add(usage)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+24
-32
@@ -25,7 +25,6 @@ import com.intellij.psi.*
|
|||||||
import com.intellij.psi.search.searches.ReferencesSearch
|
import com.intellij.psi.search.searches.ReferencesSearch
|
||||||
import com.intellij.refactoring.util.RefactoringUIUtil
|
import com.intellij.refactoring.util.RefactoringUIUtil
|
||||||
import com.intellij.util.containers.MultiMap
|
import com.intellij.util.containers.MultiMap
|
||||||
import org.jetbrains.kotlin.asJava.namedUnwrappedElement
|
|
||||||
import org.jetbrains.kotlin.descriptors.CallableDescriptor
|
import org.jetbrains.kotlin.descriptors.CallableDescriptor
|
||||||
import org.jetbrains.kotlin.idea.caches.resolve.analyze
|
import org.jetbrains.kotlin.idea.caches.resolve.analyze
|
||||||
import org.jetbrains.kotlin.idea.caches.resolve.resolveToDescriptorIfAny
|
import org.jetbrains.kotlin.idea.caches.resolve.resolveToDescriptorIfAny
|
||||||
@@ -51,11 +50,12 @@ import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
|
|||||||
import org.jetbrains.kotlin.resolve.scopes.utils.findFunction
|
import org.jetbrains.kotlin.resolve.scopes.utils.findFunction
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
class ConvertPropertyToFunctionIntention : SelfTargetingIntention<KtProperty>(KtProperty::class.java, "Convert property to function"), LowPriorityAction {
|
class ConvertPropertyToFunctionIntention : SelfTargetingIntention<KtProperty>(KtProperty::class.java, "Convert property to function"),
|
||||||
|
LowPriorityAction {
|
||||||
private inner class Converter(
|
private inner class Converter(
|
||||||
project: Project,
|
project: Project,
|
||||||
descriptor: CallableDescriptor
|
descriptor: CallableDescriptor
|
||||||
): CallableRefactoring<CallableDescriptor>(project, descriptor, text) {
|
) : CallableRefactoring<CallableDescriptor>(project, descriptor, text) {
|
||||||
private val newName: String = JvmAbi.getterName(callableDescriptor.name.asString())
|
private val newName: String = JvmAbi.getterName(callableDescriptor.name.asString())
|
||||||
|
|
||||||
private fun convertProperty(originalProperty: KtProperty, psiFactory: KtPsiFactory) {
|
private fun convertProperty(originalProperty: KtProperty, psiFactory: KtPsiFactory) {
|
||||||
@@ -69,14 +69,14 @@ class ConvertPropertyToFunctionIntention : SelfTargetingIntention<KtProperty>(Kt
|
|||||||
if (property.initializer == null) {
|
if (property.initializer == null) {
|
||||||
if (getter != null) {
|
if (getter != null) {
|
||||||
val dropGetterTo = (getter.equalsToken ?: getter.bodyExpression)
|
val dropGetterTo = (getter.equalsToken ?: getter.bodyExpression)
|
||||||
?.siblings(forward = false, withItself = false)
|
?.siblings(forward = false, withItself = false)
|
||||||
?.firstOrNull { it !is PsiWhiteSpace }
|
?.firstOrNull { it !is PsiWhiteSpace }
|
||||||
getter.deleteChildRange(getter.firstChild, dropGetterTo)
|
getter.deleteChildRange(getter.firstChild, dropGetterTo)
|
||||||
|
|
||||||
val dropPropertyFrom = getter
|
val dropPropertyFrom = getter
|
||||||
.siblings(forward = false, withItself = false)
|
.siblings(forward = false, withItself = false)
|
||||||
.first { it !is PsiWhiteSpace }
|
.first { it !is PsiWhiteSpace }
|
||||||
.nextSibling
|
.nextSibling
|
||||||
property.deleteChildRange(dropPropertyFrom, getter.prevSibling)
|
property.deleteChildRange(dropPropertyFrom, getter.prevSibling)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -97,9 +97,9 @@ class ConvertPropertyToFunctionIntention : SelfTargetingIntention<KtProperty>(Kt
|
|||||||
|
|
||||||
project.runSynchronouslyWithProgress("Looking for usages and conflicts...", true) {
|
project.runSynchronouslyWithProgress("Looking for usages and conflicts...", true) {
|
||||||
runReadAction {
|
runReadAction {
|
||||||
val progressStep = 1.0/callables.size
|
val progressStep = 1.0 / callables.size
|
||||||
for ((i, callable) in callables.withIndex()) {
|
for ((i, callable) in callables.withIndex()) {
|
||||||
ProgressManager.getInstance().progressIndicatorNullable!!.fraction = (i + 1)*progressStep
|
ProgressManager.getInstance().progressIndicatorNullable!!.fraction = (i + 1) * progressStep
|
||||||
|
|
||||||
if (callable !is PsiNamedElement) continue
|
if (callable !is PsiNamedElement) continue
|
||||||
|
|
||||||
@@ -110,17 +110,10 @@ class ConvertPropertyToFunctionIntention : SelfTargetingIntention<KtProperty>(Kt
|
|||||||
|
|
||||||
if (callable is KtProperty) {
|
if (callable is KtProperty) {
|
||||||
callableDescriptor.getContainingScope()
|
callableDescriptor.getContainingScope()
|
||||||
?.findFunction(callableDescriptor.name, NoLookupLocation.FROM_IDE) { it.valueParameters.isEmpty() }
|
?.findFunction(callableDescriptor.name, NoLookupLocation.FROM_IDE) { it.valueParameters.isEmpty() }
|
||||||
?.let { DescriptorToSourceUtilsIde.getAnyDeclaration(project, it) }
|
?.let { DescriptorToSourceUtilsIde.getAnyDeclaration(project, it) }
|
||||||
?.let { reportDeclarationConflict(conflicts, it) { "$it already exists" } }
|
?.let { reportDeclarationConflict(conflicts, it) { s -> "$s already exists" } }
|
||||||
}
|
} else if (callable is PsiMethod) callable.checkDeclarationConflict(propertyName, conflicts, callables)
|
||||||
else if (callable is PsiMethod) {
|
|
||||||
callable.containingClass
|
|
||||||
?.findMethodsByName(propertyName, true)
|
|
||||||
// as is necessary here: see KT-10386
|
|
||||||
?.firstOrNull { it.parameterList.parametersCount == 0 && !callables.contains(it.namedUnwrappedElement as PsiElement?) }
|
|
||||||
?.let { reportDeclarationConflict(conflicts, it) { "$it already exists" } }
|
|
||||||
}
|
|
||||||
|
|
||||||
val usages = ReferencesSearch.search(callable)
|
val usages = ReferencesSearch.search(callable)
|
||||||
for (usage in usages) {
|
for (usage in usages) {
|
||||||
@@ -128,18 +121,17 @@ class ConvertPropertyToFunctionIntention : SelfTargetingIntention<KtProperty>(Kt
|
|||||||
if (usage is KtSimpleNameReference) {
|
if (usage is KtSimpleNameReference) {
|
||||||
val expression = usage.expression
|
val expression = usage.expression
|
||||||
if (expression.getCall(expression.analyze(BodyResolveMode.PARTIAL)) != null
|
if (expression.getCall(expression.analyze(BodyResolveMode.PARTIAL)) != null
|
||||||
&& expression.getStrictParentOfType<KtCallableReferenceExpression>() == null) {
|
&& expression.getStrictParentOfType<KtCallableReferenceExpression>() == null
|
||||||
|
) {
|
||||||
kotlinRefsToReplaceWithCall.add(expression)
|
kotlinRefsToReplaceWithCall.add(expression)
|
||||||
}
|
} else if (nameChanged) {
|
||||||
else if (nameChanged) {
|
|
||||||
refsToRename.add(usage)
|
refsToRename.add(usage)
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
val refElement = usage.element
|
val refElement = usage.element
|
||||||
conflicts.putValue(
|
conflicts.putValue(
|
||||||
refElement,
|
refElement,
|
||||||
"Unrecognized reference will be skipped: " + StringUtil.htmlEmphasize(refElement.text)
|
"Unrecognized reference will be skipped: " + StringUtil.htmlEmphasize(refElement.text)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
continue
|
continue
|
||||||
@@ -157,8 +149,8 @@ class ConvertPropertyToFunctionIntention : SelfTargetingIntention<KtProperty>(Kt
|
|||||||
}
|
}
|
||||||
|
|
||||||
conflicts.putValue(
|
conflicts.putValue(
|
||||||
refElement,
|
refElement,
|
||||||
"Can't replace foreign reference with call expression: " + StringUtil.htmlEmphasize(refElement.text)
|
"Can't replace foreign reference with call expression: " + StringUtil.htmlEmphasize(refElement.text)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,7 +28,10 @@ import com.intellij.openapi.project.Project
|
|||||||
import com.intellij.openapi.roots.JavaProjectRootsUtil
|
import com.intellij.openapi.roots.JavaProjectRootsUtil
|
||||||
import com.intellij.openapi.ui.DialogWrapper
|
import com.intellij.openapi.ui.DialogWrapper
|
||||||
import com.intellij.openapi.ui.Messages
|
import com.intellij.openapi.ui.Messages
|
||||||
import com.intellij.openapi.ui.popup.*
|
import com.intellij.openapi.ui.popup.JBPopup
|
||||||
|
import com.intellij.openapi.ui.popup.JBPopupAdapter
|
||||||
|
import com.intellij.openapi.ui.popup.JBPopupFactory
|
||||||
|
import com.intellij.openapi.ui.popup.LightweightWindowEvent
|
||||||
import com.intellij.openapi.util.Pass
|
import com.intellij.openapi.util.Pass
|
||||||
import com.intellij.openapi.util.TextRange
|
import com.intellij.openapi.util.TextRange
|
||||||
import com.intellij.openapi.util.text.StringUtil
|
import com.intellij.openapi.util.text.StringUtil
|
||||||
@@ -82,7 +85,6 @@ import org.jetbrains.kotlin.lexer.KtTokens
|
|||||||
import org.jetbrains.kotlin.name.FqName
|
import org.jetbrains.kotlin.name.FqName
|
||||||
import org.jetbrains.kotlin.name.FqNameUnsafe
|
import org.jetbrains.kotlin.name.FqNameUnsafe
|
||||||
import org.jetbrains.kotlin.psi.*
|
import org.jetbrains.kotlin.psi.*
|
||||||
import org.jetbrains.kotlin.psi.codeFragmentUtil.suppressDiagnosticsInDebugMode
|
|
||||||
import org.jetbrains.kotlin.psi.psiUtil.*
|
import org.jetbrains.kotlin.psi.psiUtil.*
|
||||||
import org.jetbrains.kotlin.renderer.DescriptorRenderer
|
import org.jetbrains.kotlin.renderer.DescriptorRenderer
|
||||||
import org.jetbrains.kotlin.resolve.*
|
import org.jetbrains.kotlin.resolve.*
|
||||||
@@ -95,21 +97,25 @@ import java.lang.annotation.Retention
|
|||||||
import java.util.*
|
import java.util.*
|
||||||
import javax.swing.Icon
|
import javax.swing.Icon
|
||||||
|
|
||||||
val CHECK_SUPER_METHODS_YES_NO_DIALOG = "CHECK_SUPER_METHODS_YES_NO_DIALOG"
|
const val CHECK_SUPER_METHODS_YES_NO_DIALOG = "CHECK_SUPER_METHODS_YES_NO_DIALOG"
|
||||||
|
|
||||||
@JvmOverloads
|
@JvmOverloads
|
||||||
fun getOrCreateKotlinFile(fileName: String,
|
fun getOrCreateKotlinFile(
|
||||||
targetDir: PsiDirectory,
|
fileName: String,
|
||||||
packageName: String? = targetDir.getPackage()?.qualifiedName): KtFile? =
|
targetDir: PsiDirectory,
|
||||||
(targetDir.findFile(fileName) ?: createKotlinFile(fileName, targetDir, packageName)) as? KtFile
|
packageName: String? = targetDir.getPackage()?.qualifiedName
|
||||||
|
): KtFile? =
|
||||||
|
(targetDir.findFile(fileName) ?: createKotlinFile(fileName, targetDir, packageName)) as? KtFile
|
||||||
|
|
||||||
fun createKotlinFile(fileName: String,
|
fun createKotlinFile(
|
||||||
targetDir: PsiDirectory,
|
fileName: String,
|
||||||
packageName: String? = targetDir.getPackage()?.qualifiedName): KtFile {
|
targetDir: PsiDirectory,
|
||||||
|
packageName: String? = targetDir.getPackage()?.qualifiedName
|
||||||
|
): KtFile {
|
||||||
targetDir.checkCreateFile(fileName)
|
targetDir.checkCreateFile(fileName)
|
||||||
val packageFqName = packageName?.let(::FqName) ?: FqName.ROOT
|
val packageFqName = packageName?.let(::FqName) ?: FqName.ROOT
|
||||||
val file = PsiFileFactory.getInstance(targetDir.project).createFileFromText(
|
val file = PsiFileFactory.getInstance(targetDir.project).createFileFromText(
|
||||||
fileName, KotlinFileType.INSTANCE, if (!packageFqName.isRoot) "package ${packageFqName.quoteSegmentsIfNeeded()} \n\n" else ""
|
fileName, KotlinFileType.INSTANCE, if (!packageFqName.isRoot) "package ${packageFqName.quoteSegmentsIfNeeded()} \n\n" else ""
|
||||||
)
|
)
|
||||||
|
|
||||||
return targetDir.add(file) as KtFile
|
return targetDir.add(file) as KtFile
|
||||||
@@ -127,24 +133,25 @@ fun VirtualFile.toPsiFile(project: Project): PsiFile? = PsiManager.getInstance(p
|
|||||||
|
|
||||||
fun VirtualFile.toPsiDirectory(project: Project): PsiDirectory? = PsiManager.getInstance(project).findDirectory(this)
|
fun VirtualFile.toPsiDirectory(project: Project): PsiDirectory? = PsiManager.getInstance(project).findDirectory(this)
|
||||||
|
|
||||||
fun VirtualFile.toPsiFileOrDirectory(project: Project): PsiFileSystemItem? = if (isDirectory) toPsiDirectory(project) else toPsiFile(project)
|
fun VirtualFile.toPsiFileOrDirectory(project: Project): PsiFileSystemItem? =
|
||||||
|
if (isDirectory) toPsiDirectory(project) else toPsiFile(project)
|
||||||
|
|
||||||
fun PsiElement.getUsageContext(): PsiElement {
|
fun PsiElement.getUsageContext(): PsiElement {
|
||||||
return when (this) {
|
return when (this) {
|
||||||
is KtElement -> PsiTreeUtil.getParentOfType(
|
is KtElement -> PsiTreeUtil.getParentOfType(
|
||||||
this,
|
this,
|
||||||
KtPropertyAccessor::class.java,
|
KtPropertyAccessor::class.java,
|
||||||
KtProperty::class.java,
|
KtProperty::class.java,
|
||||||
KtNamedFunction::class.java,
|
KtNamedFunction::class.java,
|
||||||
KtConstructor::class.java,
|
KtConstructor::class.java,
|
||||||
KtClassOrObject::class.java
|
KtClassOrObject::class.java
|
||||||
) ?: containingFile
|
) ?: containingFile
|
||||||
else -> ConflictsUtil.getContainer(this)
|
else -> ConflictsUtil.getContainer(this)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun PsiElement.isInJavaSourceRoot(): Boolean =
|
fun PsiElement.isInJavaSourceRoot(): Boolean =
|
||||||
!JavaProjectRootsUtil.isOutsideJavaSourceRoot(containingFile)
|
!JavaProjectRootsUtil.isOutsideJavaSourceRoot(containingFile)
|
||||||
|
|
||||||
fun KtFile.createTempCopy(text: String? = null): KtFile {
|
fun KtFile.createTempCopy(text: String? = null): KtFile {
|
||||||
val tmpFile = KtPsiFactory(this).createAnalyzableFile(name, text ?: this.text ?: "", this)
|
val tmpFile = KtPsiFactory(this).createAnalyzableFile(name, text ?: this.text ?: "", this)
|
||||||
@@ -171,8 +178,8 @@ fun PsiElement.getAllExtractionContainers(strict: Boolean = true): List<KtElemen
|
|||||||
if (!objectOrNonInnerNestedClassFound) {
|
if (!objectOrNonInnerNestedClassFound) {
|
||||||
val bodyParent = (element as? KtClassBody)?.parent
|
val bodyParent = (element as? KtClassBody)?.parent
|
||||||
objectOrNonInnerNestedClassFound =
|
objectOrNonInnerNestedClassFound =
|
||||||
(bodyParent is KtObjectDeclaration && !bodyParent.isObjectLiteral())
|
(bodyParent is KtObjectDeclaration && !bodyParent.isObjectLiteral())
|
||||||
|| (bodyParent is KtClass && !bodyParent.isInner())
|
|| (bodyParent is KtClass && !bodyParent.isInner())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -182,13 +189,13 @@ fun PsiElement.getAllExtractionContainers(strict: Boolean = true): List<KtElemen
|
|||||||
fun PsiElement.getExtractionContainers(strict: Boolean = true, includeAll: Boolean = false): List<KtElement> {
|
fun PsiElement.getExtractionContainers(strict: Boolean = true, includeAll: Boolean = false): List<KtElement> {
|
||||||
fun getEnclosingDeclaration(element: PsiElement, strict: Boolean): PsiElement? {
|
fun getEnclosingDeclaration(element: PsiElement, strict: Boolean): PsiElement? {
|
||||||
return (if (strict) element.parents else element.parentsWithSelf)
|
return (if (strict) element.parents else element.parentsWithSelf)
|
||||||
.filter {
|
.filter {
|
||||||
(it is KtDeclarationWithBody && it !is KtFunctionLiteral && !(it is KtNamedFunction && it.name == null))
|
(it is KtDeclarationWithBody && it !is KtFunctionLiteral && !(it is KtNamedFunction && it.name == null))
|
||||||
|| it is KtAnonymousInitializer
|
|| it is KtAnonymousInitializer
|
||||||
|| it is KtClassBody
|
|| it is KtClassBody
|
||||||
|| it is KtFile
|
|| it is KtFile
|
||||||
}
|
}
|
||||||
.firstOrNull()
|
.firstOrNull()
|
||||||
}
|
}
|
||||||
|
|
||||||
if (includeAll) return getAllExtractionContainers(strict)
|
if (includeAll) return getAllExtractionContainers(strict)
|
||||||
@@ -212,9 +219,10 @@ fun PsiElement.getExtractionContainers(strict: Boolean = true, includeAll: Boole
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun Project.checkConflictsInteractively(
|
fun Project.checkConflictsInteractively(
|
||||||
conflicts: MultiMap<PsiElement, String>,
|
conflicts: MultiMap<PsiElement, String>,
|
||||||
onShowConflicts: () -> Unit = {},
|
onShowConflicts: () -> Unit = {},
|
||||||
onAccept: () -> Unit) {
|
onAccept: () -> Unit
|
||||||
|
) {
|
||||||
if (!conflicts.isEmpty) {
|
if (!conflicts.isEmpty) {
|
||||||
if (ApplicationManager.getApplication()!!.isUnitTestMode) throw ConflictsInTestsException(conflicts.values())
|
if (ApplicationManager.getApplication()!!.isUnitTestMode) throw ConflictsInTestsException(conflicts.values())
|
||||||
|
|
||||||
@@ -232,21 +240,22 @@ fun Project.checkConflictsInteractively(
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun reportDeclarationConflict(
|
fun reportDeclarationConflict(
|
||||||
conflicts: MultiMap<PsiElement, String>,
|
conflicts: MultiMap<PsiElement, String>,
|
||||||
declaration: PsiElement,
|
declaration: PsiElement,
|
||||||
message: (renderedDeclaration: String) -> String
|
message: (renderedDeclaration: String) -> String
|
||||||
) {
|
) {
|
||||||
conflicts.putValue(declaration, message(RefactoringUIUtil.getDescription(declaration, true).capitalize()))
|
conflicts.putValue(declaration, message(RefactoringUIUtil.getDescription(declaration, true).capitalize()))
|
||||||
}
|
}
|
||||||
|
|
||||||
fun <T, E : PsiElement> getPsiElementPopup(
|
fun <T, E : PsiElement> getPsiElementPopup(
|
||||||
editor: Editor,
|
editor: Editor,
|
||||||
elements: List<T>,
|
elements: List<T>,
|
||||||
renderer: PsiElementListCellRenderer<E>,
|
renderer: PsiElementListCellRenderer<E>,
|
||||||
title: String?,
|
title: String?,
|
||||||
highlightSelection: Boolean,
|
highlightSelection: Boolean,
|
||||||
toPsi: (T) -> E,
|
toPsi: (T) -> E,
|
||||||
processor: (T) -> Boolean): JBPopup {
|
processor: (T) -> Boolean
|
||||||
|
): JBPopup {
|
||||||
val highlighter = if (highlightSelection) SelectionAwareScopeHighlighter(editor) else null
|
val highlighter = if (highlightSelection) SelectionAwareScopeHighlighter(editor) else null
|
||||||
|
|
||||||
val list = JBList(elements.map(toPsi))
|
val list = JBList(elements.map(toPsi))
|
||||||
@@ -283,13 +292,13 @@ class SelectionAwareScopeHighlighter(val editor: Editor) {
|
|||||||
|
|
||||||
private fun addHighlighter(r: TextRange, attr: TextAttributes) {
|
private fun addHighlighter(r: TextRange, attr: TextAttributes) {
|
||||||
highlighters.add(
|
highlighters.add(
|
||||||
editor.markupModel.addRangeHighlighter(
|
editor.markupModel.addRangeHighlighter(
|
||||||
r.startOffset,
|
r.startOffset,
|
||||||
r.endOffset,
|
r.endOffset,
|
||||||
UnwrapHandler.HIGHLIGHTER_LEVEL,
|
UnwrapHandler.HIGHLIGHTER_LEVEL,
|
||||||
attr,
|
attr,
|
||||||
HighlighterTargetArea.EXACT_RANGE
|
HighlighterTargetArea.EXACT_RANGE
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -359,84 +368,85 @@ class SeparateFileWrapper(manager: PsiManager) : LightElement(manager, KotlinLan
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun <T> chooseContainerElement(
|
fun <T> chooseContainerElement(
|
||||||
containers: List<T>,
|
containers: List<T>,
|
||||||
editor: Editor,
|
editor: Editor,
|
||||||
title: String,
|
title: String,
|
||||||
highlightSelection: Boolean,
|
highlightSelection: Boolean,
|
||||||
toPsi: (T) -> PsiElement,
|
toPsi: (T) -> PsiElement,
|
||||||
onSelect: (T) -> Unit) {
|
onSelect: (T) -> Unit
|
||||||
|
) {
|
||||||
return getPsiElementPopup(
|
return getPsiElementPopup(
|
||||||
editor,
|
editor,
|
||||||
containers,
|
containers,
|
||||||
object : PsiElementListCellRenderer<PsiElement>() {
|
object : PsiElementListCellRenderer<PsiElement>() {
|
||||||
private fun PsiElement.renderName(): String {
|
private fun PsiElement.renderName(): String {
|
||||||
if (this is KtPropertyAccessor) {
|
if (this is KtPropertyAccessor) {
|
||||||
return property.renderName() + if (isGetter) ".get" else ".set"
|
return property.renderName() + if (isGetter) ".get" else ".set"
|
||||||
}
|
|
||||||
if (this is KtObjectDeclaration && this.isCompanion()) {
|
|
||||||
return "Companion object of ${getStrictParentOfType<KtClassOrObject>()?.renderName() ?: "<anonymous>"}"
|
|
||||||
}
|
|
||||||
return (this as? PsiNamedElement)?.name ?: "<anonymous>"
|
|
||||||
}
|
}
|
||||||
|
if (this is KtObjectDeclaration && this.isCompanion()) {
|
||||||
private fun PsiElement.renderDeclaration(): String? {
|
return "Companion object of ${getStrictParentOfType<KtClassOrObject>()?.renderName() ?: "<anonymous>"}"
|
||||||
if (this is KtFunctionLiteral || isFunctionalExpression()) return renderText()
|
|
||||||
|
|
||||||
val descriptor = when {
|
|
||||||
this is KtFile -> name
|
|
||||||
this is KtElement -> analyze()[BindingContext.DECLARATION_TO_DESCRIPTOR, this]
|
|
||||||
this is PsiMember -> getJavaMemberDescriptor()
|
|
||||||
else -> null
|
|
||||||
} ?: return null
|
|
||||||
val name = renderName()
|
|
||||||
val params = (descriptor as? FunctionDescriptor)?.valueParameters
|
|
||||||
?.map { DescriptorRenderer.Companion.SHORT_NAMES_IN_TYPES.renderType(it.type) }
|
|
||||||
?.joinToString(", ", "(", ")") ?: ""
|
|
||||||
return "$name$params"
|
|
||||||
}
|
}
|
||||||
|
return (this as? PsiNamedElement)?.name ?: "<anonymous>"
|
||||||
private fun PsiElement.renderText(): String {
|
|
||||||
if (this is SeparateFileWrapper) return "Extract to separate file"
|
|
||||||
return StringUtil.shortenTextWithEllipsis(text!!.collapseSpaces(), 53, 0)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun PsiElement.getRepresentativeElement(): PsiElement {
|
|
||||||
return when (this) {
|
|
||||||
is KtBlockExpression -> (parent as? KtDeclarationWithBody) ?: this
|
|
||||||
is KtClassBody -> parent as KtClassOrObject
|
|
||||||
else -> this
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun getElementText(element: PsiElement): String? {
|
|
||||||
val representativeElement = element.getRepresentativeElement()
|
|
||||||
return representativeElement.renderDeclaration() ?: representativeElement.renderText()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun getContainerText(element: PsiElement, name: String?): String? = null
|
|
||||||
|
|
||||||
override fun getIconFlags(): Int = 0
|
|
||||||
|
|
||||||
override fun getIcon(element: PsiElement): Icon? =
|
|
||||||
super.getIcon(element.getRepresentativeElement())
|
|
||||||
},
|
|
||||||
title,
|
|
||||||
highlightSelection,
|
|
||||||
toPsi,
|
|
||||||
{
|
|
||||||
onSelect(it)
|
|
||||||
true
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun PsiElement.renderDeclaration(): String? {
|
||||||
|
if (this is KtFunctionLiteral || isFunctionalExpression()) return renderText()
|
||||||
|
|
||||||
|
val descriptor = when {
|
||||||
|
this is KtFile -> name
|
||||||
|
this is KtElement -> analyze()[BindingContext.DECLARATION_TO_DESCRIPTOR, this]
|
||||||
|
this is PsiMember -> getJavaMemberDescriptor()
|
||||||
|
else -> null
|
||||||
|
} ?: return null
|
||||||
|
val name = renderName()
|
||||||
|
val params = (descriptor as? FunctionDescriptor)?.valueParameters
|
||||||
|
?.map { DescriptorRenderer.Companion.SHORT_NAMES_IN_TYPES.renderType(it.type) }
|
||||||
|
?.joinToString(", ", "(", ")") ?: ""
|
||||||
|
return "$name$params"
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun PsiElement.renderText(): String {
|
||||||
|
if (this is SeparateFileWrapper) return "Extract to separate file"
|
||||||
|
return StringUtil.shortenTextWithEllipsis(text!!.collapseSpaces(), 53, 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun PsiElement.getRepresentativeElement(): PsiElement {
|
||||||
|
return when (this) {
|
||||||
|
is KtBlockExpression -> (parent as? KtDeclarationWithBody) ?: this
|
||||||
|
is KtClassBody -> parent as KtClassOrObject
|
||||||
|
else -> this
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getElementText(element: PsiElement): String? {
|
||||||
|
val representativeElement = element.getRepresentativeElement()
|
||||||
|
return representativeElement.renderDeclaration() ?: representativeElement.renderText()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getContainerText(element: PsiElement, name: String?): String? = null
|
||||||
|
|
||||||
|
override fun getIconFlags(): Int = 0
|
||||||
|
|
||||||
|
override fun getIcon(element: PsiElement): Icon? =
|
||||||
|
super.getIcon(element.getRepresentativeElement())
|
||||||
|
},
|
||||||
|
title,
|
||||||
|
highlightSelection,
|
||||||
|
toPsi,
|
||||||
|
{
|
||||||
|
onSelect(it)
|
||||||
|
true
|
||||||
|
}
|
||||||
).showInBestPositionFor(editor)
|
).showInBestPositionFor(editor)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun <T> chooseContainerElementIfNecessary(
|
fun <T> chooseContainerElementIfNecessary(
|
||||||
containers: List<T>,
|
containers: List<T>,
|
||||||
editor: Editor,
|
editor: Editor,
|
||||||
title: String,
|
title: String,
|
||||||
highlightSelection: Boolean,
|
highlightSelection: Boolean,
|
||||||
toPsi: (T) -> PsiElement,
|
toPsi: (T) -> PsiElement,
|
||||||
onSelect: (T) -> Unit
|
onSelect: (T) -> Unit
|
||||||
) {
|
) {
|
||||||
when {
|
when {
|
||||||
containers.isEmpty() -> return
|
containers.isEmpty() -> return
|
||||||
@@ -454,8 +464,8 @@ fun PsiElement.canRefactor(): Boolean {
|
|||||||
this is PsiPackage ->
|
this is PsiPackage ->
|
||||||
directories.any { it.canRefactor() }
|
directories.any { it.canRefactor() }
|
||||||
this is KtElement ||
|
this is KtElement ||
|
||||||
this is PsiMember && language == JavaLanguage.INSTANCE ||
|
this is PsiMember && language == JavaLanguage.INSTANCE ||
|
||||||
this is PsiDirectory ->
|
this is PsiDirectory ->
|
||||||
ProjectRootsUtil.isInProjectSource(this, includeScriptsOutsideSourceRoots = true)
|
ProjectRootsUtil.isInProjectSource(this, includeScriptsOutsideSourceRoots = true)
|
||||||
else ->
|
else ->
|
||||||
false
|
false
|
||||||
@@ -480,9 +490,9 @@ private fun copyModifierListItems(from: PsiModifierList, to: PsiModifierList, wi
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun <T> copyTypeParameters(
|
private fun <T> copyTypeParameters(
|
||||||
from: T,
|
from: T,
|
||||||
to: T,
|
to: T,
|
||||||
inserter: (T, PsiTypeParameterList) -> Unit
|
inserter: (T, PsiTypeParameterList) -> Unit
|
||||||
) where T : PsiTypeParameterListOwner, T : PsiNameIdentifierOwner {
|
) where T : PsiTypeParameterListOwner, T : PsiNameIdentifierOwner {
|
||||||
val factory = PsiElementFactory.SERVICE.getInstance((from as PsiElement).project)
|
val factory = PsiElementFactory.SERVICE.getInstance((from as PsiElement).project)
|
||||||
val templateTypeParams = from.typeParameterList?.typeParameters ?: PsiTypeParameter.EMPTY_ARRAY
|
val templateTypeParams = from.typeParameterList?.typeParameters ?: PsiTypeParameter.EMPTY_ARRAY
|
||||||
@@ -493,17 +503,17 @@ private fun <T> copyTypeParameters(
|
|||||||
factory.createTypeParameter(it.name, it.extendsList.referencedTypes)
|
factory.createTypeParameter(it.name, it.extendsList.referencedTypes)
|
||||||
}
|
}
|
||||||
ChangeSignatureUtil.synchronizeList(
|
ChangeSignatureUtil.synchronizeList(
|
||||||
targetTypeParamList,
|
targetTypeParamList,
|
||||||
newTypeParams,
|
newTypeParams,
|
||||||
{ it!!.typeParameters.toList() },
|
{ it!!.typeParameters.toList() },
|
||||||
BooleanArray(newTypeParams.size)
|
BooleanArray(newTypeParams.size)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun createJavaMethod(function: KtFunction, targetClass: PsiClass): PsiMethod {
|
fun createJavaMethod(function: KtFunction, targetClass: PsiClass): PsiMethod {
|
||||||
val template = LightClassUtil.getLightClassMethod(function)
|
val template = LightClassUtil.getLightClassMethod(function)
|
||||||
?: throw AssertionError("Can't generate light method: ${function.getElementTextWithContext()}")
|
?: throw AssertionError("Can't generate light method: ${function.getElementTextWithContext()}")
|
||||||
return createJavaMethod(template, targetClass)
|
return createJavaMethod(template, targetClass)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -511,8 +521,7 @@ fun createJavaMethod(template: PsiMethod, targetClass: PsiClass): PsiMethod {
|
|||||||
val factory = PsiElementFactory.SERVICE.getInstance(template.project)
|
val factory = PsiElementFactory.SERVICE.getInstance(template.project)
|
||||||
val methodToAdd = if (template.isConstructor) {
|
val methodToAdd = if (template.isConstructor) {
|
||||||
factory.createConstructor(template.name)
|
factory.createConstructor(template.name)
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
factory.createMethod(template.name, template.returnType)
|
factory.createMethod(template.name, template.returnType)
|
||||||
}
|
}
|
||||||
val method = targetClass.add(methodToAdd) as PsiMethod
|
val method = targetClass.add(methodToAdd) as PsiMethod
|
||||||
@@ -533,16 +542,15 @@ fun createJavaMethod(template: PsiMethod, targetClass: PsiClass): PsiMethod {
|
|||||||
param
|
param
|
||||||
}
|
}
|
||||||
ChangeSignatureUtil.synchronizeList(
|
ChangeSignatureUtil.synchronizeList(
|
||||||
targetParamList,
|
targetParamList,
|
||||||
newParams,
|
newParams,
|
||||||
{ it.parameters.toList() },
|
{ it.parameters.toList() },
|
||||||
BooleanArray(newParams.size)
|
BooleanArray(newParams.size)
|
||||||
)
|
)
|
||||||
|
|
||||||
if (template.modifierList.hasModifierProperty(PsiModifier.ABSTRACT) || targetClass.isInterface) {
|
if (template.modifierList.hasModifierProperty(PsiModifier.ABSTRACT) || targetClass.isInterface) {
|
||||||
method.body!!.delete()
|
method.body!!.delete()
|
||||||
}
|
} else if (!template.isConstructor) {
|
||||||
else if (!template.isConstructor) {
|
|
||||||
CreateFromUsageUtils.setupMethodBody(method)
|
CreateFromUsageUtils.setupMethodBody(method)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -552,7 +560,7 @@ fun createJavaMethod(template: PsiMethod, targetClass: PsiClass): PsiMethod {
|
|||||||
fun createJavaField(property: KtNamedDeclaration, targetClass: PsiClass): PsiField {
|
fun createJavaField(property: KtNamedDeclaration, targetClass: PsiClass): PsiField {
|
||||||
val accessorLightMethods = property.getAccessorLightMethods()
|
val accessorLightMethods = property.getAccessorLightMethods()
|
||||||
val template = accessorLightMethods.getter
|
val template = accessorLightMethods.getter
|
||||||
?: throw AssertionError("Can't generate light method: ${property.getElementTextWithContext()}")
|
?: throw AssertionError("Can't generate light method: ${property.getElementTextWithContext()}")
|
||||||
|
|
||||||
val factory = PsiElementFactory.SERVICE.getInstance(template.project)
|
val factory = PsiElementFactory.SERVICE.getInstance(template.project)
|
||||||
val field = targetClass.add(factory.createField(property.name!!, template.returnType!!)) as PsiField
|
val field = targetClass.add(factory.createField(property.name!!, template.returnType!!)) as PsiField
|
||||||
@@ -597,21 +605,20 @@ fun createJavaClass(klass: KtClass, targetClass: PsiClass?, forcePlainClass: Boo
|
|||||||
// Turning interface to class
|
// Turning interface to class
|
||||||
if (!javaClass.isInterface && template.isInterface) {
|
if (!javaClass.isInterface && template.isInterface) {
|
||||||
val implementsList = factory.createReferenceListWithRole(
|
val implementsList = factory.createReferenceListWithRole(
|
||||||
template.extendsList?.referenceElements ?: PsiJavaCodeReferenceElement.EMPTY_ARRAY,
|
template.extendsList?.referenceElements ?: PsiJavaCodeReferenceElement.EMPTY_ARRAY,
|
||||||
PsiReferenceList.Role.IMPLEMENTS_LIST
|
PsiReferenceList.Role.IMPLEMENTS_LIST
|
||||||
)
|
)
|
||||||
implementsList?.let { javaClass.implementsList?.replace(it) }
|
implementsList?.let { javaClass.implementsList?.replace(it) }
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
val extendsList = factory.createReferenceListWithRole(
|
val extendsList = factory.createReferenceListWithRole(
|
||||||
template.extendsList?.referenceElements ?: PsiJavaCodeReferenceElement.EMPTY_ARRAY,
|
template.extendsList?.referenceElements ?: PsiJavaCodeReferenceElement.EMPTY_ARRAY,
|
||||||
PsiReferenceList.Role.EXTENDS_LIST
|
PsiReferenceList.Role.EXTENDS_LIST
|
||||||
)
|
)
|
||||||
extendsList?.let { javaClass.extendsList?.replace(it) }
|
extendsList?.let { javaClass.extendsList?.replace(it) }
|
||||||
|
|
||||||
val implementsList = factory.createReferenceListWithRole(
|
val implementsList = factory.createReferenceListWithRole(
|
||||||
template.implementsList?.referenceElements ?: PsiJavaCodeReferenceElement.EMPTY_ARRAY,
|
template.implementsList?.referenceElements ?: PsiJavaCodeReferenceElement.EMPTY_ARRAY,
|
||||||
PsiReferenceList.Role.IMPLEMENTS_LIST
|
PsiReferenceList.Role.IMPLEMENTS_LIST
|
||||||
)
|
)
|
||||||
implementsList?.let { javaClass.implementsList?.replace(it) }
|
implementsList?.let { javaClass.implementsList?.replace(it) }
|
||||||
}
|
}
|
||||||
@@ -619,9 +626,9 @@ fun createJavaClass(klass: KtClass, targetClass: PsiClass?, forcePlainClass: Boo
|
|||||||
for (method in template.methods) {
|
for (method in template.methods) {
|
||||||
val hasParams = method.parameterList.parametersCount > 0
|
val hasParams = method.parameterList.parametersCount > 0
|
||||||
val needSuperCall = !template.isEnum &&
|
val needSuperCall = !template.isEnum &&
|
||||||
(template.superClass?.constructors ?: PsiMethod.EMPTY_ARRAY).all {
|
(template.superClass?.constructors ?: PsiMethod.EMPTY_ARRAY).all {
|
||||||
it.parameterList.parametersCount > 0
|
it.parameterList.parametersCount > 0
|
||||||
}
|
}
|
||||||
if (method.isConstructor && !(hasParams || needSuperCall)) continue
|
if (method.isConstructor && !(hasParams || needSuperCall)) continue
|
||||||
with(createJavaMethod(method, javaClass)) {
|
with(createJavaMethod(method, javaClass)) {
|
||||||
if (isConstructor && needSuperCall) {
|
if (isConstructor && needSuperCall) {
|
||||||
@@ -636,9 +643,11 @@ fun createJavaClass(klass: KtClass, targetClass: PsiClass?, forcePlainClass: Boo
|
|||||||
fun PsiElement.j2kText(): String? {
|
fun PsiElement.j2kText(): String? {
|
||||||
if (language != JavaLanguage.INSTANCE) return null
|
if (language != JavaLanguage.INSTANCE) return null
|
||||||
|
|
||||||
val j2kConverter = JavaToKotlinConverter(project,
|
val j2kConverter = JavaToKotlinConverter(
|
||||||
ConverterSettings.Companion.defaultSettings,
|
project,
|
||||||
IdeaJavaToKotlinServices)
|
ConverterSettings.Companion.defaultSettings,
|
||||||
|
IdeaJavaToKotlinServices
|
||||||
|
)
|
||||||
return j2kConverter.elementsToKotlin(listOf(this)).results.single()?.text ?: return null //TODO: insert imports
|
return j2kConverter.elementsToKotlin(listOf(this)).results.single()?.text ?: return null //TODO: insert imports
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -669,52 +678,52 @@ internal abstract class CompositeRefactoringRunner(
|
|||||||
fun run() {
|
fun run() {
|
||||||
val connection = project.messageBus.connect()
|
val connection = project.messageBus.connect()
|
||||||
connection.subscribe(
|
connection.subscribe(
|
||||||
RefactoringEventListener.REFACTORING_EVENT_TOPIC,
|
RefactoringEventListener.REFACTORING_EVENT_TOPIC,
|
||||||
object : RefactoringEventListener {
|
object : RefactoringEventListener {
|
||||||
override fun undoRefactoring(refactoringId: String) {
|
override fun undoRefactoring(refactoringId: String) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun refactoringStarted(refactoringId: String, beforeData: RefactoringEventData?) {
|
override fun refactoringStarted(refactoringId: String, beforeData: RefactoringEventData?) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun conflictsDetected(refactoringId: String, conflictsData: RefactoringEventData) {
|
override fun conflictsDetected(refactoringId: String, conflictsData: RefactoringEventData) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun refactoringDone(refactoringId: String, afterData: RefactoringEventData?) {
|
override fun refactoringDone(refactoringId: String, afterData: RefactoringEventData?) {
|
||||||
if (refactoringId == this@CompositeRefactoringRunner.refactoringId) {
|
if (refactoringId == this@CompositeRefactoringRunner.refactoringId) {
|
||||||
onRefactoringDone()
|
onRefactoringDone()
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
)
|
)
|
||||||
connection.subscribe(
|
connection.subscribe(
|
||||||
KotlinRefactoringEventListener.EVENT_TOPIC,
|
KotlinRefactoringEventListener.EVENT_TOPIC,
|
||||||
object : KotlinRefactoringEventListener {
|
object : KotlinRefactoringEventListener {
|
||||||
override fun onRefactoringExit(refactoringId: String) {
|
override fun onRefactoringExit(refactoringId: String) {
|
||||||
if (refactoringId == this@CompositeRefactoringRunner.refactoringId) {
|
if (refactoringId == this@CompositeRefactoringRunner.refactoringId) {
|
||||||
try {
|
try {
|
||||||
onExit()
|
onExit()
|
||||||
} finally {
|
} finally {
|
||||||
connection.disconnect()
|
connection.disconnect()
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
)
|
)
|
||||||
runRefactoring()
|
runRefactoring()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Throws(ConfigurationException::class) fun KtElement?.validateElement(errorMessage: String) {
|
@Throws(ConfigurationException::class)
|
||||||
|
fun KtElement?.validateElement(errorMessage: String) {
|
||||||
if (this == null) throw ConfigurationException(errorMessage)
|
if (this == null) throw ConfigurationException(errorMessage)
|
||||||
|
|
||||||
try {
|
try {
|
||||||
AnalyzingUtils.checkForSyntacticErrors(this)
|
AnalyzingUtils.checkForSyntacticErrors(this)
|
||||||
}
|
} catch (e: Exception) {
|
||||||
catch(e: Exception) {
|
|
||||||
throw ConfigurationException(errorMessage)
|
throw ConfigurationException(errorMessage)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -743,7 +752,7 @@ fun PsiNamedElement.isInterfaceClass(): Boolean = when (this) {
|
|||||||
|
|
||||||
fun KtNamedDeclaration.isAbstract(): Boolean {
|
fun KtNamedDeclaration.isAbstract(): Boolean {
|
||||||
if (hasModifier(KtTokens.ABSTRACT_KEYWORD)) return true
|
if (hasModifier(KtTokens.ABSTRACT_KEYWORD)) return true
|
||||||
if (!(containingClassOrObject?.isInterfaceClass() ?: false)) return false
|
if (containingClassOrObject?.isInterfaceClass() != true) return false
|
||||||
return when (this) {
|
return when (this) {
|
||||||
is KtProperty -> initializer == null && delegate == null && accessors.isEmpty()
|
is KtProperty -> initializer == null && delegate == null && accessors.isEmpty()
|
||||||
is KtNamedFunction -> !hasBody()
|
is KtNamedFunction -> !hasBody()
|
||||||
@@ -754,10 +763,10 @@ fun KtNamedDeclaration.isAbstract(): Boolean {
|
|||||||
fun KtNamedDeclaration.isConstructorDeclaredProperty() = this is KtParameter && ownerFunction is KtPrimaryConstructor && hasValOrVar()
|
fun KtNamedDeclaration.isConstructorDeclaredProperty() = this is KtParameter && ownerFunction is KtPrimaryConstructor && hasValOrVar()
|
||||||
|
|
||||||
fun <ListType : KtElement> replaceListPsiAndKeepDelimiters(
|
fun <ListType : KtElement> replaceListPsiAndKeepDelimiters(
|
||||||
originalList: ListType,
|
originalList: ListType,
|
||||||
newList: ListType,
|
newList: ListType,
|
||||||
@Suppress("UNCHECKED_CAST") listReplacer: ListType.(ListType) -> ListType = { replace(it) as ListType },
|
@Suppress("UNCHECKED_CAST") listReplacer: ListType.(ListType) -> ListType = { replace(it) as ListType },
|
||||||
itemsFun: ListType.() -> List<KtElement>
|
itemsFun: ListType.() -> List<KtElement>
|
||||||
): ListType {
|
): ListType {
|
||||||
originalList.children.takeWhile { it is PsiErrorElement }.forEach { it.delete() }
|
originalList.children.takeWhile { it is PsiErrorElement }.forEach { it.delete() }
|
||||||
|
|
||||||
@@ -767,7 +776,7 @@ fun <ListType : KtElement> replaceListPsiAndKeepDelimiters(
|
|||||||
val newCount = newParameters.size
|
val newCount = newParameters.size
|
||||||
|
|
||||||
val commonCount = Math.min(oldCount, newCount)
|
val commonCount = Math.min(oldCount, newCount)
|
||||||
for (i in 0..commonCount - 1) {
|
for (i in 0 until commonCount) {
|
||||||
oldParameters[i] = oldParameters[i].replace(newParameters[i]) as KtElement
|
oldParameters[i] = oldParameters[i].replace(newParameters[i]) as KtElement
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -777,10 +786,10 @@ fun <ListType : KtElement> replaceListPsiAndKeepDelimiters(
|
|||||||
|
|
||||||
if (oldCount > commonCount) {
|
if (oldCount > commonCount) {
|
||||||
originalList.deleteChildRange(oldParameters[commonCount - 1].nextSibling, lastOriginalParameter)
|
originalList.deleteChildRange(oldParameters[commonCount - 1].nextSibling, lastOriginalParameter)
|
||||||
}
|
} else if (newCount > commonCount) {
|
||||||
else if (newCount > commonCount) {
|
|
||||||
val psiBeforeLastParameter = lastOriginalParameter.prevSibling
|
val psiBeforeLastParameter = lastOriginalParameter.prevSibling
|
||||||
val withMultiline = (psiBeforeLastParameter is PsiWhiteSpace || psiBeforeLastParameter is PsiComment) && psiBeforeLastParameter.textContains('\n')
|
val withMultiline =
|
||||||
|
(psiBeforeLastParameter is PsiWhiteSpace || psiBeforeLastParameter is PsiComment) && psiBeforeLastParameter.textContains('\n')
|
||||||
val extraSpace = if (withMultiline) KtPsiFactory(originalList).createNewLine() else null
|
val extraSpace = if (withMultiline) KtPsiFactory(originalList).createNewLine() else null
|
||||||
originalList.addRangeAfter(newParameters[commonCount - 1].nextSibling, newParameters.last(), lastOriginalParameter)
|
originalList.addRangeAfter(newParameters[commonCount - 1].nextSibling, newParameters.last(), lastOriginalParameter)
|
||||||
if (extraSpace != null) {
|
if (extraSpace != null) {
|
||||||
@@ -850,7 +859,7 @@ internal fun DeclarationDescriptor.getThisLabelName(): String {
|
|||||||
if (this is AnonymousFunctionDescriptor) {
|
if (this is AnonymousFunctionDescriptor) {
|
||||||
val function = source.getPsi() as? KtFunction
|
val function = source.getPsi() as? KtFunction
|
||||||
val argument = function?.parent as? KtValueArgument
|
val argument = function?.parent as? KtValueArgument
|
||||||
?: (function?.parent as? KtLambdaExpression)?.parent as? KtValueArgument
|
?: (function?.parent as? KtLambdaExpression)?.parent as? KtValueArgument
|
||||||
val callElement = argument?.getStrictParentOfType<KtCallElement>()
|
val callElement = argument?.getStrictParentOfType<KtCallElement>()
|
||||||
val callee = callElement?.calleeExpression as? KtSimpleNameExpression
|
val callee = callElement?.calleeExpression as? KtSimpleNameExpression
|
||||||
if (callee != null) return callee.text
|
if (callee != null) return callee.text
|
||||||
@@ -874,9 +883,9 @@ val PsiElement.isInsideInjectedFragment: Boolean
|
|||||||
get() = containingFile.isInjectedFragment
|
get() = containingFile.isInjectedFragment
|
||||||
|
|
||||||
fun checkSuperMethods(
|
fun checkSuperMethods(
|
||||||
declaration: KtDeclaration,
|
declaration: KtDeclaration,
|
||||||
ignore: Collection<PsiElement>?,
|
ignore: Collection<PsiElement>?,
|
||||||
actionString: String
|
actionString: String
|
||||||
): List<PsiElement> {
|
): List<PsiElement> {
|
||||||
fun getClassDescriptions(overriddenElementsToDescriptor: Map<PsiElement, CallableDescriptor>): List<String> {
|
fun getClassDescriptions(overriddenElementsToDescriptor: Map<PsiElement, CallableDescriptor>): List<String> {
|
||||||
return overriddenElementsToDescriptor.entries.map { entry ->
|
return overriddenElementsToDescriptor.entries.map { entry ->
|
||||||
@@ -885,7 +894,7 @@ fun checkSuperMethods(
|
|||||||
is KtNamedFunction, is KtProperty, is KtParameter -> formatClassDescriptor(descriptor.containingDeclaration)
|
is KtNamedFunction, is KtProperty, is KtParameter -> formatClassDescriptor(descriptor.containingDeclaration)
|
||||||
is PsiMethod -> {
|
is PsiMethod -> {
|
||||||
val psiClass = element.containingClass ?: error("Invalid element: ${element.getText()}")
|
val psiClass = element.containingClass ?: error("Invalid element: ${element.getText()}")
|
||||||
formatPsiClass(psiClass, true, false)
|
formatPsiClass(psiClass, markAsJava = true, inCode = false)
|
||||||
}
|
}
|
||||||
else -> error("Unexpected element: ${element.getElementTextWithContext()}")
|
else -> error("Unexpected element: ${element.getElementTextWithContext()}")
|
||||||
}
|
}
|
||||||
@@ -894,21 +903,22 @@ fun checkSuperMethods(
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun askUserForMethodsToSearch(
|
fun askUserForMethodsToSearch(
|
||||||
declarationDescriptor: CallableDescriptor,
|
declarationDescriptor: CallableDescriptor,
|
||||||
overriddenElementsToDescriptor: Map<PsiElement, CallableDescriptor>
|
overriddenElementsToDescriptor: Map<PsiElement, CallableDescriptor>
|
||||||
): List<PsiElement> {
|
): List<PsiElement> {
|
||||||
val superClassDescriptions = getClassDescriptions(overriddenElementsToDescriptor)
|
val superClassDescriptions = getClassDescriptions(overriddenElementsToDescriptor)
|
||||||
|
|
||||||
val message = KotlinBundle.message(
|
val message = KotlinBundle.message(
|
||||||
"x.overrides.y.in.class.list",
|
"x.overrides.y.in.class.list",
|
||||||
DescriptorRenderer.COMPACT_WITH_SHORT_TYPES.render(declarationDescriptor),
|
DescriptorRenderer.COMPACT_WITH_SHORT_TYPES.render(declarationDescriptor),
|
||||||
"\n${superClassDescriptions.joinToString(separator = "")}",
|
"\n${superClassDescriptions.joinToString(separator = "")}",
|
||||||
actionString
|
actionString
|
||||||
)
|
)
|
||||||
|
|
||||||
val exitCode = showYesNoCancelDialog(
|
val exitCode = showYesNoCancelDialog(
|
||||||
CHECK_SUPER_METHODS_YES_NO_DIALOG,
|
CHECK_SUPER_METHODS_YES_NO_DIALOG,
|
||||||
declaration.project, message, IdeBundle.message("title.warning"), Messages.getQuestionIcon(), Messages.YES)
|
declaration.project, message, IdeBundle.message("title.warning"), Messages.getQuestionIcon(), Messages.YES
|
||||||
|
)
|
||||||
return when (exitCode) {
|
return when (exitCode) {
|
||||||
Messages.YES -> overriddenElementsToDescriptor.keys.toList()
|
Messages.YES -> overriddenElementsToDescriptor.keys.toList()
|
||||||
Messages.NO -> listOf(declaration)
|
Messages.NO -> listOf(declaration)
|
||||||
@@ -939,11 +949,11 @@ fun checkSuperMethods(
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun checkSuperMethodsWithPopup(
|
fun checkSuperMethodsWithPopup(
|
||||||
declaration: KtNamedDeclaration,
|
declaration: KtNamedDeclaration,
|
||||||
deepestSuperMethods: List<PsiElement>,
|
deepestSuperMethods: List<PsiElement>,
|
||||||
actionString: String,
|
actionString: String,
|
||||||
editor: Editor,
|
editor: Editor,
|
||||||
action: (List<PsiElement>) -> Unit
|
action: (List<PsiElement>) -> Unit
|
||||||
) {
|
) {
|
||||||
if (deepestSuperMethods.isEmpty()) return action(listOf(declaration))
|
if (deepestSuperMethods.isEmpty()) return action(listOf(declaration))
|
||||||
|
|
||||||
@@ -974,7 +984,7 @@ fun checkSuperMethodsWithPopup(
|
|||||||
}
|
}
|
||||||
|
|
||||||
val renameBase = actionString + " base $superKind" + (if (deepestSuperMethods.size > 1) "s" else "")
|
val renameBase = actionString + " base $superKind" + (if (deepestSuperMethods.size > 1) "s" else "")
|
||||||
val renameCurrent = actionString + " only current $kind"
|
val renameCurrent = "$actionString only current $kind"
|
||||||
val title = buildString {
|
val title = buildString {
|
||||||
append(declaration.name)
|
append(declaration.name)
|
||||||
append(if (isAbstract) " implements " else " overrides ")
|
append(if (isAbstract) " implements " else " overrides ")
|
||||||
@@ -984,18 +994,18 @@ fun checkSuperMethodsWithPopup(
|
|||||||
}
|
}
|
||||||
val list = JBList<String>(renameBase, renameCurrent)
|
val list = JBList<String>(renameBase, renameCurrent)
|
||||||
JBPopupFactory.getInstance()
|
JBPopupFactory.getInstance()
|
||||||
.createListPopupBuilder(list)
|
.createListPopupBuilder(list)
|
||||||
.setTitle(title)
|
.setTitle(title)
|
||||||
.setMovable(false)
|
.setMovable(false)
|
||||||
.setResizable(false)
|
.setResizable(false)
|
||||||
.setRequestFocus(true)
|
.setRequestFocus(true)
|
||||||
.setItemChoosenCallback {
|
.setItemChoosenCallback {
|
||||||
val value = list.selectedValue ?: return@setItemChoosenCallback
|
val value = list.selectedValue ?: return@setItemChoosenCallback
|
||||||
val chosenElements = if (value == renameBase) deepestSuperMethods + declaration else listOf(declaration)
|
val chosenElements = if (value == renameBase) deepestSuperMethods + declaration else listOf(declaration)
|
||||||
action(chosenElements)
|
action(chosenElements)
|
||||||
}
|
}
|
||||||
.createPopup()
|
.createPopup()
|
||||||
.showInBestPositionFor(editor)
|
.showInBestPositionFor(editor)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun KtNamedDeclaration.isCompanionMemberOf(klass: KtClassOrObject): Boolean {
|
fun KtNamedDeclaration.isCompanionMemberOf(klass: KtClassOrObject): Boolean {
|
||||||
@@ -1016,4 +1026,12 @@ internal fun KtDeclaration.resolveToExpectedDescriptorIfPossible(): DeclarationD
|
|||||||
|
|
||||||
fun DialogWrapper.showWithTransaction() {
|
fun DialogWrapper.showWithTransaction() {
|
||||||
TransactionGuard.submitTransaction(disposable, Runnable { show() })
|
TransactionGuard.submitTransaction(disposable, Runnable { show() })
|
||||||
|
}
|
||||||
|
|
||||||
|
fun PsiMethod.checkDeclarationConflict(name: String, conflicts: MultiMap<PsiElement, String>, callables: List<PsiElement>) {
|
||||||
|
containingClass
|
||||||
|
?.findMethodsByName(name, true)
|
||||||
|
// as is necessary here: see KT-10386
|
||||||
|
?.firstOrNull { it.parameterList.parametersCount == 0 && !callables.contains(it.namedUnwrappedElement as PsiElement?) }
|
||||||
|
?.let { reportDeclarationConflict(conflicts, it) { s -> "$s already exists" } }
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user