Refactoring: inline val / fun now use the common inliner
This prevents their inconsistent work in some situations NB: breaks three tests if used alone
This commit is contained in:
+22
-11
@@ -18,6 +18,7 @@ package org.jetbrains.kotlin.idea.refactoring.inline
|
||||
|
||||
import com.intellij.lang.findUsages.DescriptiveNameUtil
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.psi.PsiElement
|
||||
import com.intellij.psi.search.GlobalSearchScope
|
||||
import com.intellij.psi.search.searches.ReferencesSearch
|
||||
import com.intellij.refactoring.BaseRefactoringProcessor
|
||||
@@ -31,25 +32,34 @@ import org.jetbrains.kotlin.idea.codeInliner.replaceUsages
|
||||
import org.jetbrains.kotlin.idea.references.KtSimpleNameReference
|
||||
import org.jetbrains.kotlin.idea.stubindex.KotlinSourceFilterScope
|
||||
import org.jetbrains.kotlin.idea.util.application.runReadAction
|
||||
import org.jetbrains.kotlin.psi.KtCallableDeclaration
|
||||
import org.jetbrains.kotlin.psi.KtNamedFunction
|
||||
import org.jetbrains.kotlin.psi.KtProperty
|
||||
import org.jetbrains.kotlin.psi.KtSimpleNameExpression
|
||||
|
||||
class KotlinInlineFunctionProcessor(
|
||||
class KotlinInlineCallableProcessor(
|
||||
project: Project,
|
||||
private val replacementStrategy: CallableUsageReplacementStrategy,
|
||||
private val function: KtNamedFunction,
|
||||
private val declaration: KtCallableDeclaration,
|
||||
private val reference: KtSimpleNameReference?,
|
||||
private val inlineThisOnly: Boolean,
|
||||
private val deleteAfter: Boolean
|
||||
private val deleteAfter: Boolean,
|
||||
private val assignments: Set<PsiElement> = emptySet()
|
||||
) : BaseRefactoringProcessor(project) {
|
||||
|
||||
private val commandName = "Inlining function ${DescriptiveNameUtil.getDescriptiveName(function)}"
|
||||
private val kind = when (declaration) {
|
||||
is KtNamedFunction -> "function"
|
||||
is KtProperty -> if (declaration.isLocal) "local variable" else "property"
|
||||
else -> "declaration"
|
||||
}
|
||||
|
||||
private val commandName = "Inlining $kind ${DescriptiveNameUtil.getDescriptiveName(declaration)}"
|
||||
|
||||
override fun findUsages(): Array<UsageInfo> {
|
||||
if (inlineThisOnly && reference != null) return arrayOf(UsageInfo(reference))
|
||||
val usages = runReadAction {
|
||||
val searchScope = KotlinSourceFilterScope.projectSources(GlobalSearchScope.projectScope(myProject), myProject)
|
||||
ReferencesSearch.search(function, searchScope)
|
||||
ReferencesSearch.search(declaration, searchScope)
|
||||
}
|
||||
return usages.map(::UsageInfo).toTypedArray()
|
||||
}
|
||||
@@ -58,20 +68,21 @@ class KotlinInlineFunctionProcessor(
|
||||
val simpleNameUsages = usages.mapNotNull { it.element as? KtSimpleNameExpression }
|
||||
replacementStrategy.replaceUsages(
|
||||
simpleNameUsages,
|
||||
function,
|
||||
declaration,
|
||||
myProject,
|
||||
commandName,
|
||||
{
|
||||
if (deleteAfter) {
|
||||
if (usages.size == simpleNameUsages.size) {
|
||||
function.delete()
|
||||
declaration.delete()
|
||||
assignments.forEach(PsiElement::delete)
|
||||
}
|
||||
else {
|
||||
CommonRefactoringUtil.showErrorHint(
|
||||
function.project,
|
||||
declaration.project,
|
||||
null,
|
||||
"Cannot inline ${usages.size - simpleNameUsages.size}/${usages.size} usages",
|
||||
"Inline Function",
|
||||
"Inline $kind",
|
||||
null
|
||||
)
|
||||
}
|
||||
@@ -90,9 +101,9 @@ class KotlinInlineFunctionProcessor(
|
||||
override fun getCodeReferencesText(usagesCount: Int, filesCount: Int) =
|
||||
RefactoringBundle.message("invocations.to.be.inlined", UsageViewBundle.getReferencesString(usagesCount, filesCount))
|
||||
|
||||
override fun getElements() = arrayOf(function)
|
||||
override fun getElements() = arrayOf(declaration)
|
||||
|
||||
override fun getProcessedElementsHeader() = "Function to inline"
|
||||
override fun getProcessedElementsHeader() = "${kind.capitalize()} to inline"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -20,7 +20,6 @@ import com.intellij.openapi.help.HelpManager
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.refactoring.HelpID
|
||||
import com.intellij.refactoring.JavaRefactoringSettings
|
||||
import com.intellij.refactoring.RefactoringBundle
|
||||
import com.intellij.refactoring.inline.InlineOptionsDialog
|
||||
import org.jetbrains.kotlin.idea.codeInliner.CallableUsageReplacementStrategy
|
||||
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder.getReturnTypeReference
|
||||
@@ -71,7 +70,7 @@ class KotlinInlineFunctionDialog(
|
||||
|
||||
public override fun doAction() {
|
||||
invokeRefactoring(
|
||||
KotlinInlineFunctionProcessor(project, replacementStrategy, function, reference,
|
||||
KotlinInlineCallableProcessor(project, replacementStrategy, function, reference,
|
||||
inlineThisOnly = isInlineThisOnly || allowInlineThisOnly,
|
||||
deleteAfter = !isInlineThisOnly && !isKeepTheDeclaration && !allowInlineThisOnly)
|
||||
)
|
||||
|
||||
@@ -17,48 +17,64 @@
|
||||
package org.jetbrains.kotlin.idea.refactoring.inline
|
||||
|
||||
import com.intellij.openapi.util.text.StringUtil
|
||||
import com.intellij.psi.PsiReference
|
||||
import com.intellij.psi.PsiElement
|
||||
import com.intellij.refactoring.JavaRefactoringSettings
|
||||
import com.intellij.refactoring.inline.AbstractInlineLocalDialog
|
||||
import com.intellij.refactoring.inline.InlineOptionsDialog
|
||||
import org.jetbrains.kotlin.idea.codeInliner.CallableUsageReplacementStrategy
|
||||
import org.jetbrains.kotlin.idea.references.KtSimpleNameReference
|
||||
import org.jetbrains.kotlin.psi.KtProperty
|
||||
|
||||
class KotlinInlineValDialog(
|
||||
element: KtProperty,
|
||||
ref: PsiReference?,
|
||||
private val occurrenceCount: Int
|
||||
) : AbstractInlineLocalDialog(element.project, element, ref, occurrenceCount) {
|
||||
private val property: KtProperty get() = myElement as KtProperty
|
||||
private val property: KtProperty,
|
||||
private val reference: KtSimpleNameReference?,
|
||||
private val replacementStrategy: CallableUsageReplacementStrategy,
|
||||
private val assignments: Set<PsiElement>
|
||||
) : InlineOptionsDialog(property.project, true, property) {
|
||||
|
||||
private var occurrenceCount = initOccurrencesNumber(property)
|
||||
|
||||
private val kind = if (property.isLocal) "local variable" else "property"
|
||||
|
||||
private val refactoringName = "Inline ${StringUtil.capitalizeWords(kind, true)}"
|
||||
|
||||
init {
|
||||
myInvokedOnReference = ref != null
|
||||
myInvokedOnReference = reference != null
|
||||
title = refactoringName
|
||||
init()
|
||||
}
|
||||
|
||||
override fun allowInlineAll() = true
|
||||
|
||||
override fun getBorderTitle() = refactoringName
|
||||
|
||||
override fun getNameLabelText() = "${kind.capitalize()} ${property.name}"
|
||||
|
||||
override fun getInlineAllText(): String? {
|
||||
val occurrencesString = if (occurrenceCount >= 0) {
|
||||
" (" + occurrenceCount + " occurrence" + (if (occurrenceCount == 1) ")" else "s)")
|
||||
} else ""
|
||||
return "Inline all references and remove the $kind" + occurrencesString
|
||||
}
|
||||
private val occurrencesString get() = if (occurrenceCount >= 0) {
|
||||
" (" + occurrenceCount + " occurrence" + (if (occurrenceCount == 1) ")" else "s)")
|
||||
} else ""
|
||||
|
||||
override fun getInlineAllText() =
|
||||
"Inline all references and remove the $kind" + occurrencesString
|
||||
|
||||
override fun getKeepTheDeclarationText(): String? =
|
||||
if (property.isWritable) "Inline all references and keep the $kind" + occurrencesString
|
||||
else super.getKeepTheDeclarationText()
|
||||
|
||||
override fun isInlineThis() = JavaRefactoringSettings.getInstance().INLINE_LOCAL_THIS
|
||||
|
||||
override fun getInlineThisText() = "Inline this occurrence and leave the $kind"
|
||||
|
||||
override fun doAction() {
|
||||
public override fun doAction() {
|
||||
invokeRefactoring(
|
||||
KotlinInlineCallableProcessor(project, replacementStrategy, property, reference,
|
||||
inlineThisOnly = isInlineThisOnly,
|
||||
deleteAfter = !isInlineThisOnly && !isKeepTheDeclaration,
|
||||
assignments = assignments)
|
||||
)
|
||||
|
||||
val settings = JavaRefactoringSettings.getInstance()
|
||||
if (myRbInlineThisOnly.isEnabled && myRbInlineAll.isEnabled) {
|
||||
settings.INLINE_LOCAL_THIS = isInlineThisOnly
|
||||
}
|
||||
close(OK_EXIT_CODE)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,51 +16,39 @@
|
||||
|
||||
package org.jetbrains.kotlin.idea.refactoring.inline
|
||||
|
||||
import com.google.common.collect.Sets
|
||||
import com.intellij.codeInsight.TargetElementUtil
|
||||
import com.intellij.lang.Language
|
||||
import com.intellij.lang.refactoring.InlineActionHandler
|
||||
import com.intellij.openapi.application.ApplicationManager
|
||||
import com.intellij.openapi.editor.Editor
|
||||
import com.intellij.openapi.editor.ex.EditorSettingsExternalizable
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.openapi.wm.WindowManager
|
||||
import com.intellij.psi.PsiElement
|
||||
import com.intellij.psi.PsiReference
|
||||
import com.intellij.psi.PsiWhiteSpace
|
||||
import com.intellij.psi.search.searches.ReferencesSearch
|
||||
import com.intellij.refactoring.HelpID
|
||||
import com.intellij.refactoring.JavaRefactoringSettings
|
||||
import com.intellij.refactoring.RefactoringBundle
|
||||
import com.intellij.refactoring.util.CommonRefactoringUtil
|
||||
import com.intellij.util.containers.MultiMap
|
||||
import org.jetbrains.kotlin.diagnostics.Errors
|
||||
import org.jetbrains.kotlin.descriptors.VariableDescriptor
|
||||
import org.jetbrains.kotlin.idea.KotlinLanguage
|
||||
import org.jetbrains.kotlin.idea.caches.resolve.analyze
|
||||
import org.jetbrains.kotlin.idea.analysis.analyzeInContext
|
||||
import org.jetbrains.kotlin.idea.caches.resolve.getResolutionFacade
|
||||
import org.jetbrains.kotlin.idea.codeInsight.shorten.performDelayedRefactoringRequests
|
||||
import org.jetbrains.kotlin.idea.core.ShortenReferences
|
||||
import org.jetbrains.kotlin.idea.core.replaced
|
||||
import org.jetbrains.kotlin.idea.refactoring.addTypeArgumentsIfNeeded
|
||||
import org.jetbrains.kotlin.idea.caches.resolve.resolveToDescriptor
|
||||
import org.jetbrains.kotlin.idea.codeInliner.CallableUsageReplacementStrategy
|
||||
import org.jetbrains.kotlin.idea.codeInliner.CodeToInlineBuilder
|
||||
import org.jetbrains.kotlin.idea.core.copied
|
||||
import org.jetbrains.kotlin.idea.refactoring.checkConflictsInteractively
|
||||
import org.jetbrains.kotlin.idea.refactoring.getQualifiedTypeArgumentList
|
||||
import org.jetbrains.kotlin.idea.references.mainReference
|
||||
import org.jetbrains.kotlin.idea.resolve.ResolutionFacade
|
||||
import org.jetbrains.kotlin.idea.util.IdeDescriptorRenderers
|
||||
import org.jetbrains.kotlin.idea.util.application.executeWriteCommand
|
||||
import org.jetbrains.kotlin.idea.references.KtSimpleNameReference
|
||||
import org.jetbrains.kotlin.idea.util.getResolutionScope
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
import org.jetbrains.kotlin.psi.psiUtil.*
|
||||
import org.jetbrains.kotlin.psi.psiUtil.getAssignmentByLHS
|
||||
import org.jetbrains.kotlin.psi.psiUtil.getQualifiedExpressionForSelectorOrThis
|
||||
import org.jetbrains.kotlin.resolve.BindingContext
|
||||
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
|
||||
import org.jetbrains.kotlin.types.ErrorUtils
|
||||
import org.jetbrains.kotlin.types.TypeUtils
|
||||
import org.jetbrains.kotlin.types.expressions.OperatorConventions
|
||||
import org.jetbrains.kotlin.utils.addIfNotNull
|
||||
import org.jetbrains.kotlin.utils.sure
|
||||
import java.util.*
|
||||
|
||||
class KotlinInlineValHandler : InlineActionHandler() {
|
||||
enum class InlineMode {
|
||||
ALL, PRIMARY, NONE
|
||||
}
|
||||
|
||||
override fun isEnabledForLanguage(l: Language) = l == KotlinLanguage.INSTANCE
|
||||
|
||||
@@ -69,46 +57,14 @@ class KotlinInlineValHandler : InlineActionHandler() {
|
||||
return element.getter == null && element.receiverTypeReference == null
|
||||
}
|
||||
|
||||
private fun doReplace(expression: KtExpression, replacement: KtExpression): List<KtExpression> {
|
||||
val parent = expression.parent
|
||||
|
||||
if (parent is KtStringTemplateEntryWithExpression &&
|
||||
replacement is KtStringTemplateExpression &&
|
||||
// Do not mix raw and non-raw templates
|
||||
parent.parent.firstChild.text == replacement.firstChild.text) {
|
||||
val entriesToAdd = replacement.entries
|
||||
val templateExpression = parent.parent as KtStringTemplateExpression
|
||||
val inlinedExpressions = if (entriesToAdd.isNotEmpty()) {
|
||||
val firstAddedEntry = templateExpression.addRangeBefore(entriesToAdd.first(), entriesToAdd.last(), parent)
|
||||
val lastNewEntry = parent.prevSibling
|
||||
val nextElement = parent.nextSibling
|
||||
if (lastNewEntry is KtSimpleNameStringTemplateEntry &&
|
||||
lastNewEntry.expression != null &&
|
||||
!canPlaceAfterSimpleNameEntry(nextElement)) {
|
||||
lastNewEntry.replace(KtPsiFactory(expression).createBlockStringTemplateEntry(lastNewEntry.expression!!))
|
||||
}
|
||||
firstAddedEntry.siblings()
|
||||
.take(entriesToAdd.size)
|
||||
.mapNotNull { (it as? KtStringTemplateEntryWithExpression)?.expression }
|
||||
.toList()
|
||||
}
|
||||
else emptyList()
|
||||
|
||||
parent.delete()
|
||||
return inlinedExpressions
|
||||
}
|
||||
|
||||
return listOf(expression.replaced(replacement))
|
||||
}
|
||||
|
||||
override fun inlineElement(project: Project, editor: Editor?, element: PsiElement) {
|
||||
val declaration = element as KtProperty
|
||||
val file = declaration.containingKtFile
|
||||
val name = declaration.name ?: return
|
||||
|
||||
val references = ReferencesSearch.search(declaration)
|
||||
val referenceExpressions = ArrayList<KtExpression>()
|
||||
val foreignUsages = ArrayList<PsiElement>()
|
||||
val referenceExpressions = mutableListOf<KtExpression>()
|
||||
val foreignUsages = mutableListOf<PsiElement>()
|
||||
for (ref in references) {
|
||||
val refElement = ref.element ?: continue
|
||||
if (refElement !is KtElement) {
|
||||
@@ -123,7 +79,7 @@ class KotlinInlineValHandler : InlineActionHandler() {
|
||||
return showErrorHint(project, editor, "$kind '$name' is never used")
|
||||
}
|
||||
|
||||
val assignments = Sets.newHashSet<PsiElement>()
|
||||
val assignments = hashSetOf<PsiElement>()
|
||||
referenceExpressions.forEach { expression ->
|
||||
val parent = expression.parent
|
||||
|
||||
@@ -147,9 +103,6 @@ class KotlinInlineValHandler : InlineActionHandler() {
|
||||
?: return reportAmbiguousAssignment(project, editor, name, assignments)
|
||||
}
|
||||
|
||||
val typeArgumentsForCall = getQualifiedTypeArgumentList(initializer)
|
||||
val parametersForFunctionLiteral = getParametersForFunctionLiteral(initializer)
|
||||
|
||||
val referencesInOriginalFile = referenceExpressions.filter { it.containingFile == file }
|
||||
val isHighlighting = referencesInOriginalFile.isNotEmpty()
|
||||
highlightElements(project, editor, referencesInOriginalFile)
|
||||
@@ -158,61 +111,36 @@ class KotlinInlineValHandler : InlineActionHandler() {
|
||||
preProcessInternalUsages(initializer, referenceExpressions)
|
||||
}
|
||||
|
||||
fun performRefactoring() {
|
||||
val primaryExpression = if (editor != null) {
|
||||
val offset = editor.caretModel.offset
|
||||
referenceExpressions.firstOrNull { it.textRange.contains(offset) }
|
||||
}
|
||||
else null
|
||||
val primaryRef = primaryExpression?.mainReference
|
||||
val descriptor = element.resolveToDescriptor() as VariableDescriptor
|
||||
val expectedType = if (element.typeReference != null)
|
||||
descriptor.returnType ?: TypeUtils.NO_EXPECTED_TYPE
|
||||
else
|
||||
TypeUtils.NO_EXPECTED_TYPE
|
||||
|
||||
val inlineMode = showDialog(declaration, primaryRef, referenceExpressions.size)
|
||||
if (inlineMode == InlineMode.NONE) {
|
||||
if (isHighlighting) {
|
||||
val initializerCopy = initializer.copied()
|
||||
fun analyzeInitializerCopy(): BindingContext {
|
||||
return initializerCopy.analyzeInContext(initializer.getResolutionScope(),
|
||||
contextExpression = initializer,
|
||||
expectedType = expectedType)
|
||||
}
|
||||
|
||||
fun performRefactoring() {
|
||||
val reference = editor?.let { TargetElementUtil.findReference(it, it.caretModel.offset) } as? KtSimpleNameReference
|
||||
val replacementBuilder = CodeToInlineBuilder(descriptor, element.getResolutionFacade())
|
||||
val replacement = replacementBuilder.prepareCodeToInline(initializerCopy, emptyList(), ::analyzeInitializerCopy)
|
||||
val replacementStrategy = CallableUsageReplacementStrategy(replacement)
|
||||
|
||||
val dialog = KotlinInlineValDialog(declaration, reference, replacementStrategy, assignments)
|
||||
|
||||
if (!ApplicationManager.getApplication().isUnitTestMode) {
|
||||
dialog.show()
|
||||
if (!dialog.isOK && isHighlighting) {
|
||||
val statusBar = WindowManager.getInstance().getStatusBar(project)
|
||||
statusBar?.info = RefactoringBundle.message("press.escape.to.remove.the.highlighting")
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
val chosenExpressions = if (inlineMode == InlineMode.ALL) referenceExpressions else listOf(primaryExpression)
|
||||
|
||||
project.executeWriteCommand(RefactoringBundle.message("inline.command", name)) {
|
||||
val inlinedExpressions = chosenExpressions
|
||||
.flatMap { referenceExpression ->
|
||||
if (assignments.contains(referenceExpression!!.parent)) return@flatMap emptyList<KtExpression>()
|
||||
|
||||
val importDirective = referenceExpression.getStrictParentOfType<KtImportDirective>()
|
||||
if (importDirective != null) {
|
||||
val reference = referenceExpression.getQualifiedElementSelector()?.mainReference
|
||||
if (reference != null && reference.multiResolve(false).size <= 1) {
|
||||
importDirective.delete()
|
||||
}
|
||||
|
||||
return@flatMap emptyList<KtExpression>()
|
||||
}
|
||||
|
||||
doReplace(referenceExpression, initializer)
|
||||
}
|
||||
.mapNotNull { postProcessInternalReferences(it) }
|
||||
|
||||
if (inlineMode == InlineMode.ALL) {
|
||||
assignments.forEach { it.delete() }
|
||||
declaration.delete()
|
||||
}
|
||||
|
||||
if (inlinedExpressions.isNotEmpty()) {
|
||||
if (typeArgumentsForCall != null) {
|
||||
inlinedExpressions.forEach { addTypeArgumentsIfNeeded(it, typeArgumentsForCall) }
|
||||
}
|
||||
|
||||
parametersForFunctionLiteral?.let { addFunctionLiteralParameterTypes(it, inlinedExpressions) }
|
||||
|
||||
if (isHighlighting) {
|
||||
highlightElements(project, editor, inlinedExpressions)
|
||||
}
|
||||
}
|
||||
performDelayedRefactoringRequests(project)
|
||||
else {
|
||||
dialog.doAction()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -238,80 +166,4 @@ class KotlinInlineValHandler : InlineActionHandler() {
|
||||
CommonRefactoringUtil.showErrorHint(project, editor, message, RefactoringBundle.message("inline.variable.title"), HelpID.INLINE_VARIABLE)
|
||||
}
|
||||
|
||||
private fun showDialog(property: KtProperty, ref: PsiReference?, occurrenceCount: Int): InlineMode {
|
||||
if (ApplicationManager.getApplication().isUnitTestMode) return InlineMode.ALL
|
||||
if ((ref == null || occurrenceCount <= 1) && !EditorSettingsExternalizable.getInstance().isShowInlineLocalDialog) return InlineMode.ALL
|
||||
|
||||
val dialog = KotlinInlineValDialog(property, ref, occurrenceCount)
|
||||
if (!dialog.showAndGet()) return InlineMode.NONE
|
||||
return if (JavaRefactoringSettings.getInstance().INLINE_LOCAL_THIS) InlineMode.PRIMARY else InlineMode.ALL
|
||||
}
|
||||
|
||||
private fun getParametersForFunctionLiteral(initializer: KtExpression): String? {
|
||||
val functionLiteralExpression = initializer.unpackFunctionLiteral(true) ?: return null
|
||||
val context = initializer.analyze(BodyResolveMode.PARTIAL)
|
||||
val lambdaDescriptor = context.get(BindingContext.FUNCTION, functionLiteralExpression.functionLiteral)
|
||||
if (lambdaDescriptor == null || ErrorUtils.containsErrorType(lambdaDescriptor)) return null
|
||||
return lambdaDescriptor.valueParameters.joinToString {
|
||||
it.name.asString() + ": " + IdeDescriptorRenderers.SOURCE_CODE.renderType(it.type)
|
||||
}
|
||||
}
|
||||
|
||||
private fun addFunctionLiteralParameterTypes(parameters: String, inlinedExpressions: List<KtExpression>) {
|
||||
val containingFile = inlinedExpressions.first().containingKtFile
|
||||
val resolutionFacade = containingFile.getResolutionFacade()
|
||||
|
||||
val functionsToAddParameters = inlinedExpressions.mapNotNull {
|
||||
val lambdaExpr = it.unpackFunctionLiteral(true).sure { "can't find function literal expression for " + it.text }
|
||||
if (needToAddParameterTypes(lambdaExpr, resolutionFacade)) lambdaExpr else null
|
||||
}
|
||||
|
||||
val psiFactory = KtPsiFactory(containingFile)
|
||||
for (lambdaExpr in functionsToAddParameters) {
|
||||
val lambda = lambdaExpr.functionLiteral
|
||||
|
||||
val currentParameterList = lambda.valueParameterList
|
||||
val newParameterList = psiFactory.createParameterList("($parameters)")
|
||||
if (currentParameterList != null) {
|
||||
currentParameterList.replace(newParameterList)
|
||||
}
|
||||
else {
|
||||
// TODO: Ugly code, need refactoring
|
||||
val openBraceElement = lambda.lBrace
|
||||
|
||||
val nextSibling = openBraceElement.nextSibling
|
||||
val whitespaceToAdd = if (nextSibling is PsiWhiteSpace && nextSibling.text.contains("\n"))
|
||||
nextSibling.copy()
|
||||
else
|
||||
null
|
||||
|
||||
val whitespaceAndArrow = psiFactory.createWhitespaceAndArrow()
|
||||
lambda.addRangeAfter(whitespaceAndArrow.first, whitespaceAndArrow.second, openBraceElement)
|
||||
|
||||
lambda.addAfter(newParameterList, openBraceElement)
|
||||
if (whitespaceToAdd != null) {
|
||||
lambda.addAfter(whitespaceToAdd, openBraceElement)
|
||||
}
|
||||
}
|
||||
ShortenReferences.DEFAULT.process(lambdaExpr.valueParameters)
|
||||
}
|
||||
}
|
||||
|
||||
private fun needToAddParameterTypes(
|
||||
lambdaExpression: KtLambdaExpression,
|
||||
resolutionFacade: ResolutionFacade
|
||||
): Boolean {
|
||||
val functionLiteral = lambdaExpression.functionLiteral
|
||||
val context = resolutionFacade.analyze(lambdaExpression, BodyResolveMode.PARTIAL_WITH_DIAGNOSTICS)
|
||||
return context.diagnostics.any { diagnostic ->
|
||||
val factory = diagnostic.factory
|
||||
val element = diagnostic.psiElement
|
||||
val hasCantInferParameter = factory == Errors.CANNOT_INFER_PARAMETER_TYPE &&
|
||||
element.parent.parent == functionLiteral
|
||||
val hasUnresolvedItOrThis = factory == Errors.UNRESOLVED_REFERENCE &&
|
||||
element.text == "it" &&
|
||||
element.getStrictParentOfType<KtFunctionLiteral>() == functionLiteral
|
||||
hasCantInferParameter || hasUnresolvedItOrThis
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Vendored
+1
-1
@@ -1,3 +1,3 @@
|
||||
fun foo() {
|
||||
val ff = {(it: Int) -> it }
|
||||
val ff = { it: Int -> it }
|
||||
}
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
fun foo() {
|
||||
val ff = {
|
||||
(it: Int) ->
|
||||
it: Int ->
|
||||
it
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -1,3 +1,3 @@
|
||||
fun foo() {
|
||||
val ff = (({(x: Int) -> x }))
|
||||
val ff = (({ x: Int -> x }))
|
||||
}
|
||||
|
||||
Vendored
+1
-1
@@ -1,3 +1,3 @@
|
||||
fun foo() {
|
||||
val ff = {(x: Int) -> x }
|
||||
val ff = { x: Int -> x }
|
||||
}
|
||||
|
||||
Vendored
+1
@@ -6,5 +6,6 @@ class Class {
|
||||
}
|
||||
|
||||
fun f() {
|
||||
Class()
|
||||
println(239)
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
// ERROR: Cannot perform refactoring.\nVariable length has no initializer
|
||||
|
||||
fun foo(s: String) {
|
||||
val l = s.<caret>length
|
||||
}
|
||||
@@ -982,6 +982,12 @@ public class InlineTestGenerated extends AbstractInlineTest {
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("Library.kt")
|
||||
public void testLibrary() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/refactoring/inline/inlineVariableOrProperty/property/Library.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("multiplePackages.kt")
|
||||
public void testMultiplePackages() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/refactoring/inline/inlineVariableOrProperty/property/multiplePackages.kt");
|
||||
|
||||
Reference in New Issue
Block a user