diff --git a/ChangeLog.md b/ChangeLog.md
index db87996d65a..3b5e0a76bdc 100644
--- a/ChangeLog.md
+++ b/ChangeLog.md
@@ -3,6 +3,13 @@
+## 1.1-M02 (EAP-2)
+
+### IDE
+
+###### New features
+- [`KT-12903`](https://youtrack.jetbrains.com/issue/KT-12903) Implement "Inline type alias" refactoring
+
## 1.1-M01 (EAP-1)
### Language features
diff --git a/idea/src/META-INF/plugin.xml b/idea/src/META-INF/plugin.xml
index fc16cff2510..0fc01886895 100644
--- a/idea/src/META-INF/plugin.xml
+++ b/idea/src/META-INF/plugin.xml
@@ -363,6 +363,7 @@
+
diff --git a/idea/src/org/jetbrains/kotlin/idea/refactoring/inline/KotlinInlineTypeAliasHandler.kt b/idea/src/org/jetbrains/kotlin/idea/refactoring/inline/KotlinInlineTypeAliasHandler.kt
new file mode 100644
index 00000000000..cd74271c71b
--- /dev/null
+++ b/idea/src/org/jetbrains/kotlin/idea/refactoring/inline/KotlinInlineTypeAliasHandler.kt
@@ -0,0 +1,199 @@
+/*
+ * Copyright 2010-2016 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.jetbrains.kotlin.idea.refactoring.inline
+
+import com.intellij.lang.Language
+import com.intellij.lang.refactoring.InlineActionHandler
+import com.intellij.openapi.editor.Editor
+import com.intellij.openapi.project.Project
+import com.intellij.openapi.wm.WindowManager
+import com.intellij.psi.PsiElement
+import com.intellij.psi.search.searches.ReferencesSearch
+import com.intellij.refactoring.HelpID
+import com.intellij.refactoring.RefactoringBundle
+import com.intellij.refactoring.util.CommonRefactoringUtil
+import org.jetbrains.kotlin.builtins.isExtensionFunctionType
+import org.jetbrains.kotlin.builtins.isFunctionType
+import org.jetbrains.kotlin.descriptors.TypeAliasDescriptor
+import org.jetbrains.kotlin.idea.KotlinLanguage
+import org.jetbrains.kotlin.idea.caches.resolve.analyze
+import org.jetbrains.kotlin.idea.caches.resolve.resolveToDescriptor
+import org.jetbrains.kotlin.idea.core.ShortenReferences
+import org.jetbrains.kotlin.idea.core.replaced
+import org.jetbrains.kotlin.idea.imports.importableFqName
+import org.jetbrains.kotlin.idea.references.KtSimpleNameReference
+import org.jetbrains.kotlin.idea.references.mainReference
+import org.jetbrains.kotlin.idea.util.IdeDescriptorRenderers
+import org.jetbrains.kotlin.idea.util.application.executeWriteCommand
+import org.jetbrains.kotlin.psi.*
+import org.jetbrains.kotlin.psi.psiUtil.*
+import org.jetbrains.kotlin.resolve.BindingContext
+import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall
+import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
+import org.jetbrains.kotlin.types.TypeProjectionImpl
+import org.jetbrains.kotlin.types.TypeSubstitutor
+import org.jetbrains.kotlin.types.Variance
+
+class KotlinInlineTypeAliasHandler : InlineActionHandler() {
+ companion object {
+ val REFACTORING_NAME = "Inline Type Alias"
+ }
+
+ private fun showErrorHint(project: Project, editor: Editor?, message: String) {
+ CommonRefactoringUtil.showErrorHint(project, editor, message, REFACTORING_NAME, null)
+ }
+
+ override fun isEnabledForLanguage(l: Language?) = l == KotlinLanguage.INSTANCE
+
+ override fun canInlineElement(element: PsiElement?) = element is KtTypeAlias
+
+ override fun inlineElement(project: Project, editor: Editor?, element: PsiElement) {
+ val typeAlias = element as? KtTypeAlias ?: return
+ val name = typeAlias.name ?: return
+ val aliasBody = typeAlias.getTypeReference() ?: return
+ val file = typeAlias.getContainingKtFile()
+
+ val typeAliasDescriptor = typeAlias.resolveToDescriptor() as TypeAliasDescriptor
+ val typeToInline = typeAliasDescriptor.expandedType
+ val typeConstructorsToInline = typeAliasDescriptor.typeConstructor.parameters.map { it.typeConstructor }
+
+ val usages = ReferencesSearch.search(typeAlias).mapNotNull {
+ val refElement = it.element
+ refElement.getParentOfTypeAndBranch { referenceExpression }
+ ?: refElement.getNonStrictParentOfType()
+ }
+
+ if (usages.isEmpty()) return showErrorHint(project, editor, "Type alias '$name' is never used")
+
+ val usagesInOriginalFile = usages.filter { it.containingFile == file }
+ val isHighlighting = usagesInOriginalFile.isNotEmpty()
+ highlightElements(project, editor, usagesInOriginalFile)
+
+ if (usagesInOriginalFile.size != usages.size) {
+ preProcessInternalUsages(aliasBody, usages)
+ }
+
+ if (!showDialog(project,
+ name,
+ REFACTORING_NAME,
+ typeAlias,
+ usages,
+ HelpID.INLINE_VARIABLE)) {
+ if (isHighlighting) {
+ val statusBar = WindowManager.getInstance().getStatusBar(project)
+ statusBar?.info = RefactoringBundle.message("press.escape.to.remove.the.highlighting")
+ }
+ return
+ }
+
+ val psiFactory = KtPsiFactory(project)
+
+ fun inlineIntoType(usage: KtUserType): KtElement? {
+ val context = usage.analyze(BodyResolveMode.PARTIAL)
+
+ val argumentTypes = usage
+ .typeArguments
+ .filterNotNull()
+ .mapNotNull {
+ val type = context[BindingContext.ABBREVIATED_TYPE, it.typeReference] ?:
+ context[BindingContext.TYPE, it.typeReference]
+ if (type != null) TypeProjectionImpl(type) else null
+ }
+ if (argumentTypes.size != typeConstructorsToInline.size) return null
+ val substitution = (typeConstructorsToInline zip argumentTypes).toMap()
+ val substitutor = TypeSubstitutor.create(substitution)
+ val expandedType = substitutor.substitute(typeToInline, Variance.INVARIANT) ?: return null
+ val expandedTypeText = IdeDescriptorRenderers.SOURCE_CODE.renderType(expandedType)
+ val needParentheses =
+ (expandedType.isFunctionType && usage.parent is KtNullableType) ||
+ (expandedType.isExtensionFunctionType && usage.getParentOfTypeAndBranch { receiverTypeReference } != null)
+ val expandedTypeReference = psiFactory.createType(expandedTypeText)
+ return usage.replaced(expandedTypeReference.typeElement!!).apply {
+ if (needParentheses) {
+ val sample = psiFactory.createParameterList("()")
+ parent.addBefore(sample.firstChild, this)
+ parent.addAfter(sample.lastChild, this)
+ }
+ }
+ }
+
+ fun inlineIntoCall(usage: KtReferenceExpression): KtElement? {
+ val context = usage.analyze(BodyResolveMode.PARTIAL)
+
+ val importDirective = usage.getStrictParentOfType()
+ if (importDirective != null) {
+ val reference = usage.getQualifiedElementSelector()?.mainReference
+ if (reference != null && reference.multiResolve(false).size <= 1) {
+ importDirective.delete()
+ }
+
+ return null
+ }
+
+ val resolvedCall = usage.getResolvedCall(context) ?: return null
+ val callElement = resolvedCall.call.callElement as? KtCallElement ?: return null
+ val substitution = resolvedCall.typeArguments
+ .mapKeys { it.key.typeConstructor }
+ .mapValues { TypeProjectionImpl(it.value) }
+ if (substitution.size != typeConstructorsToInline.size) return null
+ val substitutor = TypeSubstitutor.create(substitution)
+ val expandedType = substitutor.substitute(typeToInline, Variance.INVARIANT) ?: return null
+ val expandedTypeFqName = expandedType.constructor.declarationDescriptor?.importableFqName ?: return null
+
+ if (expandedType.arguments.isNotEmpty()) {
+ val expandedTypeArgumentList = psiFactory.createTypeArguments(
+ expandedType.arguments.joinToString(prefix = "<",
+ postfix = ">") { IdeDescriptorRenderers.SOURCE_CODE.renderType(it.type) }
+ )
+
+ val originalTypeArgumentList = callElement.typeArgumentList
+ if (originalTypeArgumentList != null) {
+ originalTypeArgumentList.replaced(expandedTypeArgumentList)
+ }
+ else {
+ callElement.addAfter(expandedTypeArgumentList, callElement.calleeExpression)
+ }
+ }
+
+ val newCallElement = ((usage.mainReference as KtSimpleNameReference).bindToFqName(
+ expandedTypeFqName,
+ KtSimpleNameReference.ShorteningMode.NO_SHORTENING
+ ) as KtExpression).getNonStrictParentOfType()
+ return newCallElement?.getQualifiedExpressionForSelector() ?: newCallElement
+ }
+
+ project.executeWriteCommand(RefactoringBundle.message("inline.command", name)) {
+ val inlinedElements = usages.mapNotNull {
+ val inlinedElement = when (it) {
+ is KtUserType -> inlineIntoType(it)
+ is KtReferenceExpression -> inlineIntoCall(it)
+ else -> null
+ } ?: return@mapNotNull null
+
+ postProcessInternalReferences(inlinedElement)
+ }
+
+ if (inlinedElements.isNotEmpty() && isHighlighting) {
+ highlightElements(project, editor, inlinedElements)
+ }
+
+ typeAlias.delete()
+
+ ShortenReferences.DEFAULT.process(inlinedElements)
+ }
+ }
+}
\ No newline at end of file
diff --git a/idea/src/org/jetbrains/kotlin/idea/refactoring/inline/KotlinInlineValHandler.kt b/idea/src/org/jetbrains/kotlin/idea/refactoring/inline/KotlinInlineValHandler.kt
index 2cc649a3645..5abf2bff458 100644
--- a/idea/src/org/jetbrains/kotlin/idea/refactoring/inline/KotlinInlineValHandler.kt
+++ b/idea/src/org/jetbrains/kotlin/idea/refactoring/inline/KotlinInlineValHandler.kt
@@ -17,15 +17,10 @@
package org.jetbrains.kotlin.idea.refactoring.inline
import com.google.common.collect.Sets
-import com.intellij.codeInsight.highlighting.HighlightManager
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.colors.EditorColors
-import com.intellij.openapi.editor.colors.EditorColorsManager
import com.intellij.openapi.project.Project
-import com.intellij.openapi.util.Key
import com.intellij.openapi.wm.WindowManager
import com.intellij.psi.PsiElement
import com.intellij.psi.PsiWhiteSpace
@@ -33,28 +28,21 @@ import com.intellij.psi.search.searches.ReferencesSearch
import com.intellij.refactoring.HelpID
import com.intellij.refactoring.RefactoringBundle
import com.intellij.refactoring.util.CommonRefactoringUtil
-import com.intellij.refactoring.util.RefactoringMessageDialog
-import com.intellij.usageView.UsageInfo
import com.intellij.util.containers.MultiMap
import org.jetbrains.kotlin.diagnostics.Errors
import org.jetbrains.kotlin.idea.KotlinLanguage
import org.jetbrains.kotlin.idea.caches.resolve.analyze
import org.jetbrains.kotlin.idea.caches.resolve.getResolutionFacade
import org.jetbrains.kotlin.idea.codeInsight.shorten.performDelayedShortening
+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.refactoring.checkConflictsInteractively
import org.jetbrains.kotlin.idea.refactoring.getQualifiedTypeArgumentList
-import org.jetbrains.kotlin.idea.refactoring.move.ContainerChangeInfo
-import org.jetbrains.kotlin.idea.refactoring.move.ContainerInfo
-import org.jetbrains.kotlin.idea.refactoring.move.lazilyProcessInternalReferencesToUpdateOnPackageNameChange
-import org.jetbrains.kotlin.idea.refactoring.move.postProcessMoveUsages
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.core.ShortenReferences
import org.jetbrains.kotlin.idea.util.application.executeWriteCommand
-import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.*
import org.jetbrains.kotlin.resolve.BindingContext
@@ -67,11 +55,6 @@ import org.jetbrains.kotlin.utils.sure
import java.util.*
class KotlinInlineValHandler : InlineActionHandler() {
- companion object {
- private var KtSimpleNameExpression.internalUsageInfos: MutableMap UsageInfo?>?
- by CopyableUserDataProperty(Key.create("INTERNAL_USAGE_INFOS"))
- }
-
override fun isEnabledForLanguage(l: Language) = l == KotlinLanguage.INSTANCE
override fun canInlineElement(element: PsiElement): Boolean {
@@ -162,24 +145,19 @@ class KotlinInlineValHandler : InlineActionHandler() {
val referencesInOriginalFile = referenceExpressions.filter { it.containingFile == file }
val isHighlighting = referencesInOriginalFile.isNotEmpty()
- highlightExpressions(project, editor, referencesInOriginalFile)
+ highlightElements(project, editor, referencesInOriginalFile)
if (referencesInOriginalFile.size != referenceExpressions.size) {
- val targetPackages = referenceExpressions.mapNotNullTo(LinkedHashSet()) { (it.containingFile as? KtFile)?.packageFqName }
- for (targetPackage in targetPackages) {
- if (targetPackage == file.packageFqName) continue
- val packageNameInfo = ContainerChangeInfo(ContainerInfo.Package(file.packageFqName), ContainerInfo.Package(targetPackage))
- initializer.lazilyProcessInternalReferencesToUpdateOnPackageNameChange(packageNameInfo) { expr, factory ->
- val infos = expr.internalUsageInfos
- ?: LinkedHashMap UsageInfo?>()
- .apply { expr.internalUsageInfos = this }
- infos[targetPackage] = factory
- }
- }
+ preProcessInternalUsages(initializer, referenceExpressions)
}
fun performRefactoring() {
- if (!showDialog(project, name, declaration, referenceExpressions)) {
+ if (!showDialog(project,
+ name,
+ RefactoringBundle.message("inline.variable.title"),
+ declaration,
+ referenceExpressions,
+ HelpID.INLINE_VARIABLE)) {
if (isHighlighting) {
val statusBar = WindowManager.getInstance().getStatusBar(project)
statusBar?.info = RefactoringBundle.message("press.escape.to.remove.the.highlighting")
@@ -204,15 +182,7 @@ class KotlinInlineValHandler : InlineActionHandler() {
doReplace(referenceExpression, initializer)
}
- .mapNotNull { inlinedExpression ->
- val pointer = inlinedExpression.createSmartPointer()
- val targetPackage = inlinedExpression.getContainingKtFile().packageFqName
- val expressionsToProcess = inlinedExpression.collectDescendantsOfType { it.internalUsageInfos != null }
- val internalUsages = expressionsToProcess.mapNotNull { it.internalUsageInfos!![targetPackage]?.invoke(it) }
- expressionsToProcess.forEach { it.internalUsageInfos = null }
- postProcessMoveUsages(internalUsages)
- pointer.element
- }
+ .mapNotNull { postProcessInternalReferences(it) }
assignments.forEach { it.delete() }
declaration.delete()
@@ -225,7 +195,7 @@ class KotlinInlineValHandler : InlineActionHandler() {
parametersForFunctionLiteral?.let { addFunctionLiteralParameterTypes(it, inlinedExpressions) }
if (isHighlighting) {
- highlightExpressions(project, editor, inlinedExpressions)
+ highlightElements(project, editor, inlinedExpressions)
}
}
performDelayedShortening(project)
@@ -254,36 +224,6 @@ class KotlinInlineValHandler : InlineActionHandler() {
CommonRefactoringUtil.showErrorHint(project, editor, message, RefactoringBundle.message("inline.variable.title"), HelpID.INLINE_VARIABLE)
}
- private fun highlightExpressions(project: Project, editor: Editor?, elements: List) {
- if (editor == null || ApplicationManager.getApplication().isUnitTestMode) return
-
- val editorColorsManager = EditorColorsManager.getInstance()
- val searchResultsAttributes = editorColorsManager.globalScheme.getAttributes(EditorColors.SEARCH_RESULT_ATTRIBUTES)
- val highlightManager = HighlightManager.getInstance(project)
- highlightManager.addOccurrenceHighlights(editor, elements.toTypedArray(), searchResultsAttributes, true, null)
- }
-
- private fun showDialog(
- project: Project,
- name: String,
- property: KtProperty,
- referenceExpressions: List
- ): Boolean {
- if (ApplicationManager.getApplication().isUnitTestMode) return true
-
- val kind = if (property.isLocal) "local variable" else "property"
- val dialog = RefactoringMessageDialog(
- RefactoringBundle.message("inline.variable.title"),
- "Inline " + kind + " '" + name + "'? " + RefactoringBundle.message("occurences.string", referenceExpressions.size),
- HelpID.INLINE_VARIABLE,
- "OptionPane.questionIcon",
- true,
- project
- )
- dialog.show()
- return dialog.isOK
- }
-
private fun getParametersForFunctionLiteral(initializer: KtExpression): String? {
val functionLiteralExpression = initializer.unpackFunctionLiteral(true) ?: return null
val context = initializer.analyze(BodyResolveMode.PARTIAL)
diff --git a/idea/src/org/jetbrains/kotlin/idea/refactoring/inline/inlineUtils.kt b/idea/src/org/jetbrains/kotlin/idea/refactoring/inline/inlineUtils.kt
new file mode 100644
index 00000000000..f1548a6f9af
--- /dev/null
+++ b/idea/src/org/jetbrains/kotlin/idea/refactoring/inline/inlineUtils.kt
@@ -0,0 +1,102 @@
+/*
+ * Copyright 2010-2016 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.jetbrains.kotlin.idea.refactoring.inline
+
+import com.intellij.codeInsight.highlighting.HighlightManager
+import com.intellij.openapi.application.ApplicationManager
+import com.intellij.openapi.editor.Editor
+import com.intellij.openapi.editor.colors.EditorColors
+import com.intellij.openapi.editor.colors.EditorColorsManager
+import com.intellij.openapi.project.Project
+import com.intellij.openapi.util.Key
+import com.intellij.psi.PsiElement
+import com.intellij.refactoring.RefactoringBundle
+import com.intellij.refactoring.util.RefactoringMessageDialog
+import com.intellij.usageView.UsageInfo
+import org.jetbrains.kotlin.idea.refactoring.move.ContainerChangeInfo
+import org.jetbrains.kotlin.idea.refactoring.move.ContainerInfo
+import org.jetbrains.kotlin.idea.refactoring.move.lazilyProcessInternalReferencesToUpdateOnPackageNameChange
+import org.jetbrains.kotlin.idea.refactoring.move.postProcessMoveUsages
+import org.jetbrains.kotlin.name.FqName
+import org.jetbrains.kotlin.psi.*
+import org.jetbrains.kotlin.psi.psiUtil.collectDescendantsOfType
+import org.jetbrains.kotlin.psi.psiUtil.createSmartPointer
+import java.util.*
+
+fun highlightElements(project: Project, editor: Editor?, elements: List) {
+ if (editor == null || ApplicationManager.getApplication().isUnitTestMode) return
+
+ val editorColorsManager = EditorColorsManager.getInstance()
+ val searchResultsAttributes = editorColorsManager.globalScheme.getAttributes(EditorColors.SEARCH_RESULT_ATTRIBUTES)
+ val highlightManager = HighlightManager.getInstance(project)
+ highlightManager.addOccurrenceHighlights(editor, elements.toTypedArray(), searchResultsAttributes, true, null)
+}
+
+fun showDialog(
+ project: Project,
+ name: String,
+ title: String,
+ declaration: KtNamedDeclaration,
+ usages: List,
+ helpTopic: String? = null
+): Boolean {
+ if (ApplicationManager.getApplication().isUnitTestMode) return true
+
+ val kind = when (declaration) {
+ is KtProperty -> if (declaration.isLocal) "local variable" else "property"
+ is KtTypeAlias -> "type alias"
+ else -> return false
+ }
+ val dialog = RefactoringMessageDialog(
+ title,
+ "Inline " + kind + " '" + name + "'? " + RefactoringBundle.message("occurences.string", usages.size),
+ helpTopic,
+ "OptionPane.questionIcon",
+ true,
+ project
+ )
+ dialog.show()
+ return dialog.isOK
+}
+
+internal var KtSimpleNameExpression.internalUsageInfos: MutableMap UsageInfo?>?
+ by CopyableUserDataProperty(Key.create("INTERNAL_USAGE_INFOS"))
+
+internal fun preProcessInternalUsages(element: KtElement, usages: List) {
+ val mainFile = element.getContainingKtFile()
+ val targetPackages = usages.mapNotNullTo(LinkedHashSet()) { it.getContainingKtFile().packageFqName }
+ for (targetPackage in targetPackages) {
+ if (targetPackage == mainFile.packageFqName) continue
+ val packageNameInfo = ContainerChangeInfo(ContainerInfo.Package(mainFile.packageFqName), ContainerInfo.Package(targetPackage))
+ element.lazilyProcessInternalReferencesToUpdateOnPackageNameChange(packageNameInfo) { expr, factory ->
+ val infos =
+ expr.internalUsageInfos
+ ?: LinkedHashMap UsageInfo?>().apply { expr.internalUsageInfos = this }
+ infos[targetPackage] = factory
+ }
+ }
+}
+
+internal fun postProcessInternalReferences(inlinedElement: E): E? {
+ val pointer = inlinedElement.createSmartPointer()
+ val targetPackage = inlinedElement.getContainingKtFile().packageFqName
+ val expressionsToProcess = inlinedElement.collectDescendantsOfType { it.internalUsageInfos != null }
+ val internalUsages = expressionsToProcess.mapNotNull { it.internalUsageInfos!![targetPackage]?.invoke(it) }
+ expressionsToProcess.forEach { it.internalUsageInfos = null }
+ postProcessMoveUsages(internalUsages)
+ return pointer.element
+}
\ No newline at end of file
diff --git a/idea/testData/refactoring/inline/inlineTypeAlias/extensionFunctionTypeToFunctionType.kt b/idea/testData/refactoring/inline/inlineTypeAlias/extensionFunctionTypeToFunctionType.kt
new file mode 100644
index 00000000000..39bd5731b8c
--- /dev/null
+++ b/idea/testData/refactoring/inline/inlineTypeAlias/extensionFunctionTypeToFunctionType.kt
@@ -0,0 +1,7 @@
+class A
+
+typealias F = A.(A) -> A
+
+typealias G1 = (F) -> F
+typealias G2 = F.() -> F
+typealias G3 = F.(F) -> F
\ No newline at end of file
diff --git a/idea/testData/refactoring/inline/inlineTypeAlias/extensionFunctionTypeToFunctionType.kt.after b/idea/testData/refactoring/inline/inlineTypeAlias/extensionFunctionTypeToFunctionType.kt.after
new file mode 100644
index 00000000000..43fd5f4a172
--- /dev/null
+++ b/idea/testData/refactoring/inline/inlineTypeAlias/extensionFunctionTypeToFunctionType.kt.after
@@ -0,0 +1,5 @@
+class A
+
+typealias G1 = (A.(A) -> A) -> A.(A) -> A
+typealias G2 = (A.(A) -> A).() -> A.(A) -> A
+typealias G3 = (A.(A) -> A).(A.(A) -> A) -> A.(A) -> A
\ No newline at end of file
diff --git a/idea/testData/refactoring/inline/inlineTypeAlias/functionTypeToFunctionType.kt b/idea/testData/refactoring/inline/inlineTypeAlias/functionTypeToFunctionType.kt
new file mode 100644
index 00000000000..5c8894921f3
--- /dev/null
+++ b/idea/testData/refactoring/inline/inlineTypeAlias/functionTypeToFunctionType.kt
@@ -0,0 +1,7 @@
+class A
+
+typealias F = (A) -> A
+
+typealias G1 = (F) -> F
+typealias G2 = F.() -> F
+typealias G3 = F.(F) -> F
\ No newline at end of file
diff --git a/idea/testData/refactoring/inline/inlineTypeAlias/functionTypeToFunctionType.kt.after b/idea/testData/refactoring/inline/inlineTypeAlias/functionTypeToFunctionType.kt.after
new file mode 100644
index 00000000000..6810185949a
--- /dev/null
+++ b/idea/testData/refactoring/inline/inlineTypeAlias/functionTypeToFunctionType.kt.after
@@ -0,0 +1,5 @@
+class A
+
+typealias G1 = ((A) -> A) -> (A) -> A
+typealias G2 = (A) -> A.() -> (A) -> A
+typealias G3 = (A) -> A.((A) -> A) -> (A) -> A
\ No newline at end of file
diff --git a/idea/testData/refactoring/inline/inlineTypeAlias/functionTypeToNullableType.kt b/idea/testData/refactoring/inline/inlineTypeAlias/functionTypeToNullableType.kt
new file mode 100644
index 00000000000..3ef2d7a4759
--- /dev/null
+++ b/idea/testData/refactoring/inline/inlineTypeAlias/functionTypeToNullableType.kt
@@ -0,0 +1,7 @@
+class A
+
+typealias F = (A) -> A
+
+fun foo() {
+ val f: F?
+}
\ No newline at end of file
diff --git a/idea/testData/refactoring/inline/inlineTypeAlias/functionTypeToNullableType.kt.after b/idea/testData/refactoring/inline/inlineTypeAlias/functionTypeToNullableType.kt.after
new file mode 100644
index 00000000000..2db5571309b
--- /dev/null
+++ b/idea/testData/refactoring/inline/inlineTypeAlias/functionTypeToNullableType.kt.after
@@ -0,0 +1,5 @@
+class A
+
+fun foo() {
+ val f: ((A) -> A)?
+}
\ No newline at end of file
diff --git a/idea/testData/refactoring/inline/inlineTypeAlias/keepImports.1.kt b/idea/testData/refactoring/inline/inlineTypeAlias/keepImports.1.kt
new file mode 100644
index 00000000000..18881a1a5a6
--- /dev/null
+++ b/idea/testData/refactoring/inline/inlineTypeAlias/keepImports.1.kt
@@ -0,0 +1,7 @@
+package b
+
+import a.R
+
+typealias S = R
+
+fun foo() = R(1)
\ No newline at end of file
diff --git a/idea/testData/refactoring/inline/inlineTypeAlias/keepImports.1.kt.after b/idea/testData/refactoring/inline/inlineTypeAlias/keepImports.1.kt.after
new file mode 100644
index 00000000000..88145e973f9
--- /dev/null
+++ b/idea/testData/refactoring/inline/inlineTypeAlias/keepImports.1.kt.after
@@ -0,0 +1,9 @@
+package b
+
+import a.A
+import a.R
+import c.C
+
+typealias S = A>
+
+fun foo() = R(1)
\ No newline at end of file
diff --git a/idea/testData/refactoring/inline/inlineTypeAlias/keepImports.2.kt b/idea/testData/refactoring/inline/inlineTypeAlias/keepImports.2.kt
new file mode 100644
index 00000000000..774eea37762
--- /dev/null
+++ b/idea/testData/refactoring/inline/inlineTypeAlias/keepImports.2.kt
@@ -0,0 +1,3 @@
+package c
+
+class C
\ No newline at end of file
diff --git a/idea/testData/refactoring/inline/inlineTypeAlias/keepImports.2.kt.after b/idea/testData/refactoring/inline/inlineTypeAlias/keepImports.2.kt.after
new file mode 100644
index 00000000000..774eea37762
--- /dev/null
+++ b/idea/testData/refactoring/inline/inlineTypeAlias/keepImports.2.kt.after
@@ -0,0 +1,3 @@
+package c
+
+class C
\ No newline at end of file
diff --git a/idea/testData/refactoring/inline/inlineTypeAlias/keepImports.kt b/idea/testData/refactoring/inline/inlineTypeAlias/keepImports.kt
new file mode 100644
index 00000000000..4f08ce1eabc
--- /dev/null
+++ b/idea/testData/refactoring/inline/inlineTypeAlias/keepImports.kt
@@ -0,0 +1,13 @@
+package a
+
+import c.C
+
+class A
+
+typealias R = A>
+
+typealias I = R
+
+fun R(n: Int) {
+
+}
\ No newline at end of file
diff --git a/idea/testData/refactoring/inline/inlineTypeAlias/keepImports.kt.after b/idea/testData/refactoring/inline/inlineTypeAlias/keepImports.kt.after
new file mode 100644
index 00000000000..b806b3ed9f1
--- /dev/null
+++ b/idea/testData/refactoring/inline/inlineTypeAlias/keepImports.kt.after
@@ -0,0 +1,11 @@
+package a
+
+import c.C
+
+class A
+
+typealias I = A>
+
+fun R(n: Int) {
+
+}
\ No newline at end of file
diff --git a/idea/testData/refactoring/inline/inlineTypeAlias/replaceImports.1.kt b/idea/testData/refactoring/inline/inlineTypeAlias/replaceImports.1.kt
new file mode 100644
index 00000000000..dcdc38f44c5
--- /dev/null
+++ b/idea/testData/refactoring/inline/inlineTypeAlias/replaceImports.1.kt
@@ -0,0 +1,5 @@
+package b
+
+import a.R
+
+typealias S = R
\ No newline at end of file
diff --git a/idea/testData/refactoring/inline/inlineTypeAlias/replaceImports.1.kt.after b/idea/testData/refactoring/inline/inlineTypeAlias/replaceImports.1.kt.after
new file mode 100644
index 00000000000..45a5747afb7
--- /dev/null
+++ b/idea/testData/refactoring/inline/inlineTypeAlias/replaceImports.1.kt.after
@@ -0,0 +1,6 @@
+package b
+
+import a.A
+import c.C
+
+typealias S = A>
\ No newline at end of file
diff --git a/idea/testData/refactoring/inline/inlineTypeAlias/replaceImports.2.kt b/idea/testData/refactoring/inline/inlineTypeAlias/replaceImports.2.kt
new file mode 100644
index 00000000000..774eea37762
--- /dev/null
+++ b/idea/testData/refactoring/inline/inlineTypeAlias/replaceImports.2.kt
@@ -0,0 +1,3 @@
+package c
+
+class C
\ No newline at end of file
diff --git a/idea/testData/refactoring/inline/inlineTypeAlias/replaceImports.2.kt.after b/idea/testData/refactoring/inline/inlineTypeAlias/replaceImports.2.kt.after
new file mode 100644
index 00000000000..774eea37762
--- /dev/null
+++ b/idea/testData/refactoring/inline/inlineTypeAlias/replaceImports.2.kt.after
@@ -0,0 +1,3 @@
+package c
+
+class C
\ No newline at end of file
diff --git a/idea/testData/refactoring/inline/inlineTypeAlias/replaceImports.kt b/idea/testData/refactoring/inline/inlineTypeAlias/replaceImports.kt
new file mode 100644
index 00000000000..0fc546d9054
--- /dev/null
+++ b/idea/testData/refactoring/inline/inlineTypeAlias/replaceImports.kt
@@ -0,0 +1,9 @@
+package a
+
+import c.C
+
+class A
+
+typealias R = A>
+
+typealias I = R
\ No newline at end of file
diff --git a/idea/testData/refactoring/inline/inlineTypeAlias/replaceImports.kt.after b/idea/testData/refactoring/inline/inlineTypeAlias/replaceImports.kt.after
new file mode 100644
index 00000000000..29fe6d130f4
--- /dev/null
+++ b/idea/testData/refactoring/inline/inlineTypeAlias/replaceImports.kt.after
@@ -0,0 +1,7 @@
+package a
+
+import c.C
+
+class A
+
+typealias I = A>
\ No newline at end of file
diff --git a/idea/testData/refactoring/inline/inlineTypeAlias/simpleAlias.kt b/idea/testData/refactoring/inline/inlineTypeAlias/simpleAlias.kt
new file mode 100644
index 00000000000..f6a6ff49320
--- /dev/null
+++ b/idea/testData/refactoring/inline/inlineTypeAlias/simpleAlias.kt
@@ -0,0 +1,7 @@
+class A
+
+typealias X = A
+
+fun foo() {
+ val x: X = X()
+}
\ No newline at end of file
diff --git a/idea/testData/refactoring/inline/inlineTypeAlias/simpleAlias.kt.after b/idea/testData/refactoring/inline/inlineTypeAlias/simpleAlias.kt.after
new file mode 100644
index 00000000000..9d4853b0e3c
--- /dev/null
+++ b/idea/testData/refactoring/inline/inlineTypeAlias/simpleAlias.kt.after
@@ -0,0 +1,5 @@
+class A
+
+fun foo() {
+ val x: A = A()
+}
\ No newline at end of file
diff --git a/idea/tests/org/jetbrains/kotlin/idea/refactoring/inline/AbstractInlineTest.kt b/idea/tests/org/jetbrains/kotlin/idea/refactoring/inline/AbstractInlineTest.kt
index 70d5b6517c0..f7a3ebdd9ba 100644
--- a/idea/tests/org/jetbrains/kotlin/idea/refactoring/inline/AbstractInlineTest.kt
+++ b/idea/tests/org/jetbrains/kotlin/idea/refactoring/inline/AbstractInlineTest.kt
@@ -19,6 +19,8 @@ package org.jetbrains.kotlin.idea.refactoring.inline
import com.intellij.codeInsight.TargetElementUtil
import com.intellij.codeInsight.TargetElementUtil.ELEMENT_NAME_ACCEPTED
import com.intellij.codeInsight.TargetElementUtil.REFERENCED_ELEMENT_ACCEPTED
+import com.intellij.lang.refactoring.InlineActionHandler
+import com.intellij.openapi.extensions.Extensions
import com.intellij.openapi.util.io.FileUtil
import com.intellij.refactoring.util.CommonRefactoringUtil
import com.intellij.testFramework.UsefulTestCase
@@ -50,10 +52,9 @@ abstract class AbstractInlineTest : KotlinLightCodeInsightFixtureTestCase() {
val afterFileExists = afterFile.exists()
val targetElement = TargetElementUtil.findTargetElement(myFixture.editor, ELEMENT_NAME_ACCEPTED or REFERENCED_ELEMENT_ACCEPTED)!!
- val handler = KotlinInlineValHandler()
-
+ val handler = Extensions.getExtensions(InlineActionHandler.EP_NAME).firstOrNull { it.canInlineElement(targetElement) }
val expectedErrors = InTextDirectivesUtils.findLinesWithPrefixesRemoved(myFixture.file.text, "// ERROR: ")
- if (handler.canInlineElement(targetElement)) {
+ if (handler != null) {
try {
runWriteAction { handler.inlineElement(myFixture.project, myFixture.editor, targetElement) }
diff --git a/idea/tests/org/jetbrains/kotlin/idea/refactoring/inline/InlineTestGenerated.java b/idea/tests/org/jetbrains/kotlin/idea/refactoring/inline/InlineTestGenerated.java
index 3f02c7b5765..832c9604391 100644
--- a/idea/tests/org/jetbrains/kotlin/idea/refactoring/inline/InlineTestGenerated.java
+++ b/idea/tests/org/jetbrains/kotlin/idea/refactoring/inline/InlineTestGenerated.java
@@ -35,6 +35,51 @@ public class InlineTestGenerated extends AbstractInlineTest {
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/testData/refactoring/inline"), Pattern.compile("^(\\w+)\\.kt$"), true);
}
+ @TestMetadata("idea/testData/refactoring/inline/inlineTypeAlias")
+ @TestDataPath("$PROJECT_ROOT")
+ @RunWith(JUnit3RunnerWithInners.class)
+ public static class InlineTypeAlias extends AbstractInlineTest {
+ public void testAllFilesPresentInInlineTypeAlias() throws Exception {
+ KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/testData/refactoring/inline/inlineTypeAlias"), Pattern.compile("^(\\w+)\\.kt$"), true);
+ }
+
+ @TestMetadata("extensionFunctionTypeToFunctionType.kt")
+ public void testExtensionFunctionTypeToFunctionType() throws Exception {
+ String fileName = KotlinTestUtils.navigationMetadata("idea/testData/refactoring/inline/inlineTypeAlias/extensionFunctionTypeToFunctionType.kt");
+ doTest(fileName);
+ }
+
+ @TestMetadata("functionTypeToFunctionType.kt")
+ public void testFunctionTypeToFunctionType() throws Exception {
+ String fileName = KotlinTestUtils.navigationMetadata("idea/testData/refactoring/inline/inlineTypeAlias/functionTypeToFunctionType.kt");
+ doTest(fileName);
+ }
+
+ @TestMetadata("functionTypeToNullableType.kt")
+ public void testFunctionTypeToNullableType() throws Exception {
+ String fileName = KotlinTestUtils.navigationMetadata("idea/testData/refactoring/inline/inlineTypeAlias/functionTypeToNullableType.kt");
+ doTest(fileName);
+ }
+
+ @TestMetadata("keepImports.kt")
+ public void testKeepImports() throws Exception {
+ String fileName = KotlinTestUtils.navigationMetadata("idea/testData/refactoring/inline/inlineTypeAlias/keepImports.kt");
+ doTest(fileName);
+ }
+
+ @TestMetadata("replaceImports.kt")
+ public void testReplaceImports() throws Exception {
+ String fileName = KotlinTestUtils.navigationMetadata("idea/testData/refactoring/inline/inlineTypeAlias/replaceImports.kt");
+ doTest(fileName);
+ }
+
+ @TestMetadata("simpleAlias.kt")
+ public void testSimpleAlias() throws Exception {
+ String fileName = KotlinTestUtils.navigationMetadata("idea/testData/refactoring/inline/inlineTypeAlias/simpleAlias.kt");
+ doTest(fileName);
+ }
+ }
+
@TestMetadata("idea/testData/refactoring/inline/inlineVariableOrProperty")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)