Migration to expect/actual: some intentions

This commit is contained in:
Mikhail Glukhikh
2017-09-14 19:43:16 +03:00
parent 62ec4b5a31
commit 280a60af6f
6 changed files with 31 additions and 30 deletions
@@ -20,7 +20,7 @@ import com.intellij.openapi.editor.Editor
import com.intellij.openapi.util.TextRange
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.idea.caches.resolve.resolveToDescriptorIfAny
import org.jetbrains.kotlin.idea.refactoring.withHeaderImplementations
import org.jetbrains.kotlin.idea.refactoring.withExpectedActuals
import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.psi.KtNamedFunction
import org.jetbrains.kotlin.util.OperatorChecks
@@ -34,7 +34,7 @@ class AddOperatorModifierIntention : SelfTargetingRangeIntention<KtNamedFunction
}
override fun applyTo(element: KtNamedFunction, editor: Editor?) {
element.withHeaderImplementations().forEach { it.addModifier(KtTokens.OPERATOR_KEYWORD) }
element.withExpectedActuals().forEach { it.addModifier(KtTokens.OPERATOR_KEYWORD) }
}
}
@@ -23,7 +23,7 @@ import org.jetbrains.kotlin.idea.refactoring.changeSignature.KotlinChangeSignatu
import org.jetbrains.kotlin.idea.refactoring.changeSignature.KotlinMethodDescriptor
import org.jetbrains.kotlin.idea.refactoring.changeSignature.modify
import org.jetbrains.kotlin.idea.refactoring.changeSignature.runChangeSignature
import org.jetbrains.kotlin.idea.refactoring.resolveToHeaderDescriptorIfPossible
import org.jetbrains.kotlin.idea.refactoring.resolveToExpectedDescriptorIfPossible
import org.jetbrains.kotlin.psi.KtNamedFunction
import org.jetbrains.kotlin.psi.KtParameter
import org.jetbrains.kotlin.psi.psiUtil.getStrictParentOfType
@@ -52,7 +52,7 @@ class ConvertParameterToReceiverIntention : SelfTargetingIntention<KtParameter>(
override fun applyTo(element: KtParameter, editor: Editor?) {
val function = element.getStrictParentOfType<KtNamedFunction>() ?: return
val parameterIndex = function.valueParameters.indexOf(element)
val descriptor = function.resolveToHeaderDescriptorIfPossible() as? FunctionDescriptor ?: return
val descriptor = function.resolveToExpectedDescriptorIfPossible() as? FunctionDescriptor ?: return
runChangeSignature(element.project, descriptor, configureChangeSignature(parameterIndex), element, text)
}
}
@@ -28,7 +28,7 @@ import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.idea.core.getOrCreateValueParameterList
import org.jetbrains.kotlin.idea.refactoring.changeSignature.*
import org.jetbrains.kotlin.idea.refactoring.resolveToHeaderDescriptorIfPossible
import org.jetbrains.kotlin.idea.refactoring.resolveToExpectedDescriptorIfPossible
import org.jetbrains.kotlin.idea.util.application.executeWriteCommand
import org.jetbrains.kotlin.idea.util.application.runWriteAction
import org.jetbrains.kotlin.psi.KtNamedFunction
@@ -61,7 +61,7 @@ class ConvertReceiverToParameterIntention : SelfTargetingOffsetIndependentIntent
override fun applyTo(element: KtTypeReference, editor: Editor?) {
val function = element.parent as? KtNamedFunction ?: return
val descriptor = function.resolveToHeaderDescriptorIfPossible() as FunctionDescriptor
val descriptor = function.resolveToExpectedDescriptorIfPossible() as FunctionDescriptor
val project = function.project
@@ -102,7 +102,7 @@ class ConvertReceiverToParameterIntention : SelfTargetingOffsetIndependentIntent
if (!brokenOff) {
runChangeSignature(
element.project,
function.resolveToHeaderDescriptorIfPossible() as FunctionDescriptor,
function.resolveToExpectedDescriptorIfPossible() as FunctionDescriptor,
configureChangeSignature(newName),
function.receiverTypeReference!!,
text
@@ -38,7 +38,7 @@ import org.jetbrains.kotlin.idea.highlighter.markers.isExpectedOrExpectedClassMe
import org.jetbrains.kotlin.idea.highlighter.markers.liftToExpected
import org.jetbrains.kotlin.idea.intentions.SelfTargetingRangeIntention
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder.getReturnTypeReference
import org.jetbrains.kotlin.idea.refactoring.withHeaderImplementations
import org.jetbrains.kotlin.idea.refactoring.withExpectedActuals
import org.jetbrains.kotlin.idea.references.KtReference
import org.jetbrains.kotlin.idea.util.ImportInsertHelper
import org.jetbrains.kotlin.idea.util.application.runWriteAction
@@ -61,7 +61,7 @@ class ConvertMemberToExtensionIntention : SelfTargetingRangeIntention<KtCallable
}
override fun applicabilityRange(element: KtCallableDeclaration): TextRange? {
if (!element.withHeaderImplementations().all { it is KtCallableDeclaration && isApplicable(it) }) return null
if (!element.withExpectedActuals().all { it is KtCallableDeclaration && isApplicable(it) }) return null
return (element.nameIdentifier ?: return null).textRange
}
@@ -70,16 +70,16 @@ class ConvertMemberToExtensionIntention : SelfTargetingRangeIntention<KtCallable
//TODO: local class
override fun applyTo(element: KtCallableDeclaration, editor: Editor?) {
var allowHeader = true
var allowExpected = true
element.liftToExpected()?.actualsForExpected()?.let {
if (it.isEmpty()) {
allowHeader = askIfHeaderIsAllowed(element.containingKtFile)
allowExpected = askIfExpectedIsAllowed(element.containingKtFile)
}
}
runWriteAction {
val (extension, bodyToSelect) = createExtensionCallableAndPrepareBodyToSelect(element, allowHeader)
val (extension, bodyToSelect) = createExtensionCallableAndPrepareBodyToSelect(element, allowExpected)
editor?.apply {
unblockDocument()
@@ -106,12 +106,12 @@ class ConvertMemberToExtensionIntention : SelfTargetingRangeIntention<KtCallable
private fun processSingleDeclaration(
element: KtCallableDeclaration,
allowHeader: Boolean
allowExpected: Boolean
): Pair<KtCallableDeclaration, KtExpression?> {
val descriptor = element.unsafeResolveToDescriptor()
val containingClass = descriptor.containingDeclaration as ClassDescriptor
val isEffectiveHeader = allowHeader && element.isExpectedOrExpectedClassMember()
val isEffectivelyExpected = allowExpected && element.isExpectedOrExpectedClassMember()
val file = element.containingKtFile
val project = file.project
@@ -157,8 +157,9 @@ class ConvertMemberToExtensionIntention : SelfTargetingRangeIntention<KtCallable
extension.modifierList?.getModifier(KtTokens.OPEN_KEYWORD)?.delete()
extension.modifierList?.getModifier(KtTokens.FINAL_KEYWORD)?.delete()
if (isEffectiveHeader && !extension.hasModifier(KtTokens.HEADER_KEYWORD))
extension.addModifier(KtTokens.HEADER_KEYWORD)
if (isEffectivelyExpected && !extension.hasExpectModifier()) {
extension.addModifier(KtTokens.EXPECT_KEYWORD)
}
var bodyToSelect: KtExpression? = null
@@ -179,7 +180,7 @@ class ConvertMemberToExtensionIntention : SelfTargetingRangeIntention<KtCallable
when (extension) {
is KtFunction -> {
if (!extension.hasBody() && !isEffectiveHeader) {
if (!extension.hasBody() && !isEffectivelyExpected) {
//TODO: methods in PSI for setBody
extension.add(psiFactory.createBlock(bodyText))
selectBody(extension)
@@ -189,7 +190,7 @@ class ConvertMemberToExtensionIntention : SelfTargetingRangeIntention<KtCallable
is KtProperty -> {
val templateProperty = psiFactory.createDeclaration<KtProperty>("var v: Any\nget()=$bodyText\nset(value){\n$bodyText\n}")
if (!isEffectiveHeader) {
if (!isEffectivelyExpected) {
val templateGetter = templateProperty.getter!!
val templateSetter = templateProperty.setter!!
@@ -244,13 +245,13 @@ class ConvertMemberToExtensionIntention : SelfTargetingRangeIntention<KtCallable
return extension to bodyToSelect
}
private fun askIfHeaderIsAllowed(file: KtFile): Boolean {
private fun askIfExpectedIsAllowed(file: KtFile): Boolean {
if (ApplicationManager.getApplication().isUnitTestMode) {
return file.allChildren.any { it is PsiComment && it.text.trim() == "// ALLOW_HEADER_WITHOUT_IMPLS" }
}
return Messages.showYesNoDialog(
"Do you want to make new extension a header declaration?",
"Do you want to make new extension an expected declaration?",
text,
Messages.getQuestionIcon()
) == Messages.YES
@@ -258,18 +259,18 @@ class ConvertMemberToExtensionIntention : SelfTargetingRangeIntention<KtCallable
private fun createExtensionCallableAndPrepareBodyToSelect(
element: KtCallableDeclaration,
allowHeader: Boolean = true
allowExpected: Boolean = true
): Pair<KtCallableDeclaration, KtExpression?> {
val headerDeclaration = element.liftToExpected() as? KtCallableDeclaration
if (headerDeclaration != null) {
element.withHeaderImplementations().filterIsInstance<KtCallableDeclaration>().forEach {
val expectedDeclaration = element.liftToExpected() as? KtCallableDeclaration
if (expectedDeclaration != null) {
element.withExpectedActuals().filterIsInstance<KtCallableDeclaration>().forEach {
if (it != element) {
processSingleDeclaration(it, allowHeader)
processSingleDeclaration(it, allowExpected)
}
}
}
return processSingleDeclaration(element, allowHeader)
return processSingleDeclaration(element, allowExpected)
}
private fun newTypeParameterList(member: KtCallableDeclaration): KtTypeParameterList? {
@@ -967,13 +967,13 @@ fun KtNamedDeclaration.isCompanionMemberOf(klass: KtClassOrObject): Boolean {
return containingObject.isCompanion() && containingObject.containingClassOrObject == klass
}
internal fun KtDeclaration.withHeaderImplementations(): List<KtDeclaration> {
internal fun KtDeclaration.withExpectedActuals(): List<KtDeclaration> {
val header = liftToExpected() ?: return listOf(this)
val implementations = header.actualsForExpected()
return listOf(header) + implementations
}
internal fun KtDeclaration.resolveToHeaderDescriptorIfPossible(): DeclarationDescriptor {
internal fun KtDeclaration.resolveToExpectedDescriptorIfPossible(): DeclarationDescriptor {
val descriptor = unsafeResolveToDescriptor()
return descriptor.liftToExpected() ?: descriptor
}
@@ -45,7 +45,7 @@ import org.jetbrains.kotlin.idea.highlighter.markers.liftToExpected
import org.jetbrains.kotlin.idea.refactoring.checkSuperMethods
import org.jetbrains.kotlin.idea.refactoring.formatClass
import org.jetbrains.kotlin.idea.refactoring.formatFunction
import org.jetbrains.kotlin.idea.refactoring.withHeaderImplementations
import org.jetbrains.kotlin.idea.refactoring.withExpectedActuals
import org.jetbrains.kotlin.idea.references.KtReference
import org.jetbrains.kotlin.idea.search.ideaExtensions.KotlinReferencesSearchOptions
import org.jetbrains.kotlin.idea.search.ideaExtensions.KotlinReferencesSearchParameters
@@ -86,7 +86,7 @@ class KotlinSafeDeleteProcessor : JavaSafeDeleteProcessor() {
fun getSearchInfo(element: PsiElement) = NonCodeUsageSearchInfo(getIgnoranceCondition(), element)
fun searchKotlinDeclarationReferences(declaration: KtDeclaration): Sequence<PsiReference> {
val elementsToSearch = if (declaration is KtParameter) declaration.withHeaderImplementations() else listOf(declaration)
val elementsToSearch = if (declaration is KtParameter) declaration.withExpectedActuals() else listOf(declaration)
return elementsToSearch.asSequence().flatMap {
val searchParameters = KotlinReferencesSearchParameters(
it,