Refactoring

This commit is contained in:
Valentin Kipyatkov
2017-05-24 23:16:45 +03:00
parent d53aa28ddf
commit 986eaeb7ea
3 changed files with 31 additions and 41 deletions
@@ -32,7 +32,6 @@ import org.jetbrains.kotlin.idea.KotlinLanguage
import org.jetbrains.kotlin.idea.caches.resolve.analyzeFully import org.jetbrains.kotlin.idea.caches.resolve.analyzeFully
import org.jetbrains.kotlin.idea.caches.resolve.resolveToDescriptor import org.jetbrains.kotlin.idea.caches.resolve.resolveToDescriptor
import org.jetbrains.kotlin.idea.codeInliner.CallableUsageReplacementStrategy import org.jetbrains.kotlin.idea.codeInliner.CallableUsageReplacementStrategy
import org.jetbrains.kotlin.idea.codeInliner.PropertyUsageReplacementStrategy
import org.jetbrains.kotlin.idea.references.KtSimpleNameReference import org.jetbrains.kotlin.idea.references.KtSimpleNameReference
import org.jetbrains.kotlin.psi.KtExpression import org.jetbrains.kotlin.psi.KtExpression
import org.jetbrains.kotlin.psi.KtNamedFunction import org.jetbrains.kotlin.psi.KtNamedFunction
@@ -64,7 +63,14 @@ class KotlinInlineFunctionHandler: InlineActionHandler() {
} }
val descriptor = element.resolveToDescriptor() as SimpleFunctionDescriptor val descriptor = element.resolveToDescriptor() as SimpleFunctionDescriptor
val codeToInline = buildCodeToInline(element, descriptor.returnType, editor) ?: return val codeToInline = buildCodeToInline(
element,
descriptor.returnType,
element.hasDeclaredReturnType(),
element.bodyExpression!!,
element.hasBlockBody(),
editor
) ?: return
val replacementStrategy = CallableUsageReplacementStrategy(codeToInline) val replacementStrategy = CallableUsageReplacementStrategy(codeToInline)
@@ -29,22 +29,16 @@ import com.intellij.refactoring.HelpID
import com.intellij.refactoring.RefactoringBundle import com.intellij.refactoring.RefactoringBundle
import com.intellij.refactoring.util.CommonRefactoringUtil import com.intellij.refactoring.util.CommonRefactoringUtil
import com.intellij.util.containers.MultiMap import com.intellij.util.containers.MultiMap
import org.jetbrains.kotlin.descriptors.PropertyDescriptor import org.jetbrains.kotlin.descriptors.ValueDescriptor
import org.jetbrains.kotlin.descriptors.VariableDescriptor
import org.jetbrains.kotlin.idea.KotlinLanguage import org.jetbrains.kotlin.idea.KotlinLanguage
import org.jetbrains.kotlin.idea.analysis.analyzeInContext
import org.jetbrains.kotlin.idea.caches.resolve.getResolutionFacade
import org.jetbrains.kotlin.idea.caches.resolve.resolveToDescriptor import org.jetbrains.kotlin.idea.caches.resolve.resolveToDescriptor
import org.jetbrains.kotlin.idea.codeInliner.CodeToInline import org.jetbrains.kotlin.idea.codeInliner.CodeToInline
import org.jetbrains.kotlin.idea.codeInliner.CodeToInlineBuilder
import org.jetbrains.kotlin.idea.codeInliner.PropertyUsageReplacementStrategy import org.jetbrains.kotlin.idea.codeInliner.PropertyUsageReplacementStrategy
import org.jetbrains.kotlin.idea.core.copied
import org.jetbrains.kotlin.idea.project.builtIns import org.jetbrains.kotlin.idea.project.builtIns
import org.jetbrains.kotlin.idea.refactoring.checkConflictsInteractively import org.jetbrains.kotlin.idea.refactoring.checkConflictsInteractively
import org.jetbrains.kotlin.idea.references.KtSimpleNameReference import org.jetbrains.kotlin.idea.references.KtSimpleNameReference
import org.jetbrains.kotlin.idea.references.ReferenceAccess import org.jetbrains.kotlin.idea.references.ReferenceAccess
import org.jetbrains.kotlin.idea.references.readWriteAccess import org.jetbrains.kotlin.idea.references.readWriteAccess
import org.jetbrains.kotlin.idea.util.getResolutionScope
import org.jetbrains.kotlin.lexer.KtTokens import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.psi.KtBinaryExpression import org.jetbrains.kotlin.psi.KtBinaryExpression
import org.jetbrains.kotlin.psi.KtElement import org.jetbrains.kotlin.psi.KtElement
@@ -52,8 +46,6 @@ import org.jetbrains.kotlin.psi.KtExpression
import org.jetbrains.kotlin.psi.KtProperty import org.jetbrains.kotlin.psi.KtProperty
import org.jetbrains.kotlin.psi.psiUtil.getAssignmentByLHS import org.jetbrains.kotlin.psi.psiUtil.getAssignmentByLHS
import org.jetbrains.kotlin.psi.psiUtil.getQualifiedExpressionForSelectorOrThis import org.jetbrains.kotlin.psi.psiUtil.getQualifiedExpressionForSelectorOrThis
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.types.TypeUtils
class KotlinInlineValHandler : InlineActionHandler() { class KotlinInlineValHandler : InlineActionHandler() {
@@ -93,16 +85,21 @@ class KotlinInlineValHandler : InlineActionHandler() {
val readReplacement: CodeToInline? val readReplacement: CodeToInline?
val writeReplacement: CodeToInline? val writeReplacement: CodeToInline?
val assignmentToDelete: KtBinaryExpression? val assignmentToDelete: KtBinaryExpression?
val descriptor = declaration.resolveToDescriptor() as ValueDescriptor
val isTypeExplicit = declaration.typeReference != null
if (getter == null && setter == null) { if (getter == null && setter == null) {
val initialization = extractInitialization(declaration, referenceExpressions, project, editor) ?: return val initialization = extractInitialization(declaration, referenceExpressions, project, editor) ?: return
readReplacement = buildCodeToInline(declaration, initialization.value) readReplacement = buildCodeToInline(declaration, descriptor.type, isTypeExplicit, initialization.value, false, editor) ?: return
writeReplacement = null writeReplacement = null
assignmentToDelete = initialization.assignment assignmentToDelete = initialization.assignment
} }
else { else {
val descriptor = declaration.resolveToDescriptor() as PropertyDescriptor readReplacement = getter?.let {
readReplacement = getter?.let { buildCodeToInline(getter, descriptor.type, editor) ?: return } buildCodeToInline(getter, descriptor.type, isTypeExplicit, getter.bodyExpression!!, getter.hasBlockBody(), editor) ?: return
writeReplacement = setter?.let { buildCodeToInline(setter, setter.builtIns.unitType, editor) ?: return } }
writeReplacement = setter?.let {
buildCodeToInline(setter, setter.builtIns.unitType, true, setter.bodyExpression!!, setter.hasBlockBody(), editor) ?: return
}
assignmentToDelete = null assignmentToDelete = null
} }
@@ -175,24 +172,6 @@ class KotlinInlineValHandler : InlineActionHandler() {
} }
} }
private fun buildCodeToInline(declaration: KtProperty, initializer: KtExpression): CodeToInline {
val descriptor = declaration.resolveToDescriptor() as VariableDescriptor
val expectedType = if (declaration.typeReference != null)
descriptor.returnType ?: TypeUtils.NO_EXPECTED_TYPE
else
TypeUtils.NO_EXPECTED_TYPE
val initializerCopy = initializer.copied()
fun analyzeInitializerCopy(): BindingContext {
return initializerCopy.analyzeInContext(initializer.getResolutionScope(),
contextExpression = initializer,
expectedType = expectedType)
}
val codeToInlineBuilder = CodeToInlineBuilder(descriptor, declaration.getResolutionFacade())
return codeToInlineBuilder.prepareCodeToInline(initializerCopy, emptyList(), ::analyzeInitializerCopy)
}
private fun performRefactoring( private fun performRefactoring(
declaration: KtProperty, declaration: KtProperty,
readReplacement: CodeToInline?, readReplacement: CodeToInline?,
@@ -29,7 +29,6 @@ import com.intellij.refactoring.util.CommonRefactoringUtil
import com.intellij.refactoring.util.RefactoringMessageDialog import com.intellij.refactoring.util.RefactoringMessageDialog
import com.intellij.usageView.UsageInfo import com.intellij.usageView.UsageInfo
import org.jetbrains.kotlin.descriptors.CallableDescriptor import org.jetbrains.kotlin.descriptors.CallableDescriptor
import org.jetbrains.kotlin.descriptors.SimpleFunctionDescriptor
import org.jetbrains.kotlin.idea.analysis.analyzeInContext import org.jetbrains.kotlin.idea.analysis.analyzeInContext
import org.jetbrains.kotlin.idea.caches.resolve.getResolutionFacade import org.jetbrains.kotlin.idea.caches.resolve.getResolutionFacade
import org.jetbrains.kotlin.idea.caches.resolve.resolveToDescriptor import org.jetbrains.kotlin.idea.caches.resolve.resolveToDescriptor
@@ -114,24 +113,30 @@ internal fun <E : KtElement> postProcessInternalReferences(inlinedElement: E): E
return pointer.element return pointer.element
} }
internal fun buildCodeToInline(declaration: KtDeclarationWithBody, returnType: KotlinType?, editor: Editor?): CodeToInline? { internal fun buildCodeToInline(
val bodyExpression = declaration.bodyExpression!! declaration: KtDeclaration,
val bodyCopy = bodyExpression.copied() returnType: KotlinType?,
isReturnTypeExplicit: Boolean,
bodyOrInitializer: KtExpression,
isBlockBody: Boolean,
editor: Editor?
): CodeToInline? {
val bodyCopy = bodyOrInitializer.copied()
val expectedType = if (!declaration.hasBlockBody() && declaration.hasDeclaredReturnType()) val expectedType = if (!isBlockBody && isReturnTypeExplicit)
returnType ?: TypeUtils.NO_EXPECTED_TYPE returnType ?: TypeUtils.NO_EXPECTED_TYPE
else else
TypeUtils.NO_EXPECTED_TYPE TypeUtils.NO_EXPECTED_TYPE
fun analyzeBodyCopy(): BindingContext { fun analyzeBodyCopy(): BindingContext {
return bodyCopy.analyzeInContext(bodyExpression.getResolutionScope(), return bodyCopy.analyzeInContext(bodyOrInitializer.getResolutionScope(),
contextExpression = bodyExpression, contextExpression = bodyOrInitializer,
expectedType = expectedType) expectedType = expectedType)
} }
val descriptor = declaration.resolveToDescriptor() val descriptor = declaration.resolveToDescriptor()
val builder = CodeToInlineBuilder(descriptor as CallableDescriptor, declaration.getResolutionFacade()) val builder = CodeToInlineBuilder(descriptor as CallableDescriptor, declaration.getResolutionFacade())
if (declaration.hasBlockBody()) { if (isBlockBody) {
bodyCopy as KtBlockExpression bodyCopy as KtBlockExpression
val statements = bodyCopy.statements val statements = bodyCopy.statements