Inline Type Alias

#KT-12903 Fixed
This commit is contained in:
Alexey Sedunov
2016-07-15 12:03:51 +03:00
parent 7773a1c4e0
commit ccfca0e3dd
27 changed files with 496 additions and 74 deletions
+7
View File
@@ -3,6 +3,13 @@
<!-- Find: ([^\`/\[])(KT-\d+) -->
<!-- Replace: $1[`$2`](https://youtrack.jetbrains.com/issue/$2) -->
## 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
+1
View File
@@ -363,6 +363,7 @@
<refactoring.introduceParameterMethodUsagesProcessor
implementation="org.jetbrains.kotlin.idea.refactoring.introduce.introduceParameter.KotlinIntroduceParameterMethodUsageProcessor"/>
<inlineActionHandler implementation="org.jetbrains.kotlin.idea.refactoring.inline.KotlinInlineValHandler"/>
<inlineActionHandler implementation="org.jetbrains.kotlin.idea.refactoring.inline.KotlinInlineTypeAliasHandler"/>
<treeStructureProvider implementation="org.jetbrains.kotlin.idea.projectView.KotlinSelectInProjectViewProvider"/>
<treeStructureProvider implementation="org.jetbrains.kotlin.idea.projectView.KotlinExpandNodeProjectViewProvider" order="last"/>
@@ -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<KtUserType> { referenceExpression }
?: refElement.getNonStrictParentOfType<KtSimpleNameExpression>()
}
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<KtFunctionType> { 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<KtImportDirective>()
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<KtCallElement>()
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)
}
}
}
@@ -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<FqName, (KtSimpleNameExpression) -> 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<FqName, (KtSimpleNameExpression) -> 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<KtSimpleNameExpression> { 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<PsiElement>) {
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<KtExpression>
): 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)
@@ -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<PsiElement>) {
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<KtElement>,
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<FqName, (KtSimpleNameExpression) -> UsageInfo?>?
by CopyableUserDataProperty(Key.create("INTERNAL_USAGE_INFOS"))
internal fun preProcessInternalUsages(element: KtElement, usages: List<KtElement>) {
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<FqName, (KtSimpleNameExpression) -> UsageInfo?>().apply { expr.internalUsageInfos = this }
infos[targetPackage] = factory
}
}
}
internal fun <E : KtElement> postProcessInternalReferences(inlinedElement: E): E? {
val pointer = inlinedElement.createSmartPointer()
val targetPackage = inlinedElement.getContainingKtFile().packageFqName
val expressionsToProcess = inlinedElement.collectDescendantsOfType<KtSimpleNameExpression> { it.internalUsageInfos != null }
val internalUsages = expressionsToProcess.mapNotNull { it.internalUsageInfos!![targetPackage]?.invoke(it) }
expressionsToProcess.forEach { it.internalUsageInfos = null }
postProcessMoveUsages(internalUsages)
return pointer.element
}
@@ -0,0 +1,7 @@
class A
typealias <caret>F = A.(A) -> A
typealias G1 = (F) -> F
typealias G2 = F.() -> F
typealias G3 = F.(F) -> F
@@ -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
@@ -0,0 +1,7 @@
class A
typealias <caret>F = (A) -> A
typealias G1 = (F) -> F
typealias G2 = F.() -> F
typealias G3 = F.(F) -> F
@@ -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
@@ -0,0 +1,7 @@
class A
typealias <caret>F = (A) -> A
fun foo() {
val f: F?
}
@@ -0,0 +1,5 @@
class A
fun foo() {
val f: ((A) -> A)?
}
@@ -0,0 +1,7 @@
package b
import a.R
typealias S = R<Int>
fun foo() = R(1)
@@ -0,0 +1,9 @@
package b
import a.A
import a.R
import c.C
typealias S = A<C<Int>>
fun foo() = R(1)
@@ -0,0 +1,3 @@
package c
class C<X>
@@ -0,0 +1,3 @@
package c
class C<X>
@@ -0,0 +1,13 @@
package a
import c.C
class A<X>
typealias <caret>R<X> = A<C<X>>
typealias I = R<String>
fun R(n: Int) {
}
@@ -0,0 +1,11 @@
package a
import c.C
class A<X>
typealias I = A<C<String>>
fun R(n: Int) {
}
@@ -0,0 +1,5 @@
package b
import a.R
typealias S = R<Int>
@@ -0,0 +1,6 @@
package b
import a.A
import c.C
typealias S = A<C<Int>>
@@ -0,0 +1,3 @@
package c
class C<X>
@@ -0,0 +1,3 @@
package c
class C<X>
@@ -0,0 +1,9 @@
package a
import c.C
class A<X>
typealias <caret>R<X> = A<C<X>>
typealias I = R<String>
@@ -0,0 +1,7 @@
package a
import c.C
class A<X>
typealias I = A<C<String>>
@@ -0,0 +1,7 @@
class A
typealias <caret>X = A
fun foo() {
val x: X = X()
}
@@ -0,0 +1,5 @@
class A
fun foo() {
val x: A = A()
}
@@ -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) }
@@ -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)