Extraction Engine: Do not extract type parameter if it's resolved in the target scope
#KT-7246 Fixed
This commit is contained in:
+3
-3
@@ -460,14 +460,14 @@ private fun JetType.processTypeIfExtractable(
|
||||
} as? JetTypeParameter
|
||||
|
||||
when {
|
||||
typeToCheck.isResolvableInScope(targetScope, true) ->
|
||||
extractable
|
||||
|
||||
typeParameter != null -> {
|
||||
typeParameters.add(TypeParameter(typeParameter, typeParameter.collectRelevantConstraints()))
|
||||
extractable
|
||||
}
|
||||
|
||||
typeToCheck.isResolvableInScope(targetScope, false) ->
|
||||
extractable
|
||||
|
||||
options.allowSpecialClassNames && typeToCheck.isSpecial() ->
|
||||
extractable
|
||||
|
||||
|
||||
+47
-39
@@ -28,6 +28,7 @@ import org.jetbrains.kotlin.idea.util.psi.patternMatching.*
|
||||
import kotlin.test.*
|
||||
import com.intellij.openapi.application.*
|
||||
import org.jetbrains.kotlin.idea.core.refactoring.getExtractionContainers
|
||||
import org.jetbrains.kotlin.idea.refactoring.introduce.extractFunction.EXTRACT_FUNCTION
|
||||
import org.jetbrains.kotlin.idea.refactoring.introduce.introduceProperty.*
|
||||
import java.util.*
|
||||
|
||||
@@ -52,53 +53,60 @@ public class KotlinIntroducePropertyHandler(
|
||||
}
|
||||
}
|
||||
|
||||
override fun invoke(project: Project, editor: Editor, file: PsiFile, dataContext: DataContext?) {
|
||||
if (file !is JetFile) return
|
||||
public fun selectElements(editor: Editor, file: PsiFile, continuation: (elements: List<PsiElement>, targetSibling: PsiElement) -> Unit) {
|
||||
selectElementsWithTargetSibling(
|
||||
operationName = INTRODUCE_PROPERTY,
|
||||
editor = editor,
|
||||
file = file,
|
||||
getContainers = { elements, parent ->
|
||||
INTRODUCE_PROPERTY,
|
||||
editor,
|
||||
file,
|
||||
{ elements, parent ->
|
||||
parent.getExtractionContainers(strict = true, includeAll = true).filter { it is JetClassBody || it is JetFile }
|
||||
}
|
||||
) { elements, targetSibling ->
|
||||
val adjustedElements = (elements.singleOrNull() as? JetBlockExpression)?.getStatements() ?: elements
|
||||
if (adjustedElements.isNotEmpty()) {
|
||||
val options = ExtractionOptions(extractAsProperty = true)
|
||||
val extractionData = ExtractionData(file, adjustedElements.toRange(), targetSibling, null, options)
|
||||
ExtractionEngine(helper).run(editor, extractionData) {
|
||||
val property = it.declaration as JetProperty
|
||||
val descriptor = it.config.descriptor
|
||||
},
|
||||
continuation
|
||||
)
|
||||
}
|
||||
|
||||
editor.getCaretModel().moveToOffset(property.getTextOffset())
|
||||
editor.getSelectionModel().removeSelection()
|
||||
if (editor.getSettings().isVariableInplaceRenameEnabled() && !ApplicationManager.getApplication().isUnitTestMode()) {
|
||||
with(PsiDocumentManager.getInstance(project)) {
|
||||
commitDocument(editor.getDocument())
|
||||
doPostponedOperationsAndUnblockDocument(editor.getDocument())
|
||||
}
|
||||
public fun doInvoke(project: Project, editor: Editor, file: JetFile, elements: List<PsiElement>, targetSibling: PsiElement) {
|
||||
val adjustedElements = (elements.singleOrNull() as? JetBlockExpression)?.getStatements() ?: elements
|
||||
if (adjustedElements.isNotEmpty()) {
|
||||
val options = ExtractionOptions(extractAsProperty = true)
|
||||
val extractionData = ExtractionData(file, adjustedElements.toRange(), targetSibling, null, options)
|
||||
ExtractionEngine(helper).run(editor, extractionData) {
|
||||
val property = it.declaration as JetProperty
|
||||
val descriptor = it.config.descriptor
|
||||
|
||||
val introducer = KotlinInplacePropertyIntroducer(
|
||||
property = property,
|
||||
editor = editor,
|
||||
project = project,
|
||||
title = INTRODUCE_PROPERTY,
|
||||
doNotChangeVar = false,
|
||||
exprType = descriptor.controlFlow.outputValueBoxer.returnType,
|
||||
extractionResult = it,
|
||||
availableTargets = propertyTargets.filter { it.isAvailable(descriptor) }
|
||||
)
|
||||
introducer.performInplaceRefactoring(LinkedHashSet(descriptor.suggestedNames))
|
||||
}
|
||||
else {
|
||||
processDuplicatesSilently(it.duplicateReplacers, project)
|
||||
editor.getCaretModel().moveToOffset(property.getTextOffset())
|
||||
editor.getSelectionModel().removeSelection()
|
||||
if (editor.getSettings().isVariableInplaceRenameEnabled() && !ApplicationManager.getApplication().isUnitTestMode()) {
|
||||
with(PsiDocumentManager.getInstance(project)) {
|
||||
commitDocument(editor.getDocument())
|
||||
doPostponedOperationsAndUnblockDocument(editor.getDocument())
|
||||
}
|
||||
|
||||
val introducer = KotlinInplacePropertyIntroducer(
|
||||
property = property,
|
||||
editor = editor,
|
||||
project = project,
|
||||
title = INTRODUCE_PROPERTY,
|
||||
doNotChangeVar = false,
|
||||
exprType = descriptor.controlFlow.outputValueBoxer.returnType,
|
||||
extractionResult = it,
|
||||
availableTargets = propertyTargets.filter { it.isAvailable(descriptor) }
|
||||
)
|
||||
introducer.performInplaceRefactoring(LinkedHashSet(descriptor.suggestedNames))
|
||||
}
|
||||
else {
|
||||
processDuplicatesSilently(it.duplicateReplacers, project)
|
||||
}
|
||||
}
|
||||
else {
|
||||
showErrorHintByKey(project, editor, "cannot.refactor.no.expression", INTRODUCE_PROPERTY)
|
||||
}
|
||||
}
|
||||
else {
|
||||
showErrorHintByKey(project, editor, "cannot.refactor.no.expression", INTRODUCE_PROPERTY)
|
||||
}
|
||||
}
|
||||
|
||||
override fun invoke(project: Project, editor: Editor, file: PsiFile, dataContext: DataContext?) {
|
||||
if (file !is JetFile) return
|
||||
selectElements(editor, file) { elements, targetSibling -> doInvoke(project, editor, file, elements, targetSibling) }
|
||||
}
|
||||
|
||||
override fun invoke(project: Project, elements: Array<out PsiElement>, dataContext: DataContext?) {
|
||||
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
// WITH_RUNTIME
|
||||
// PARAM_TYPES: Foo<T>
|
||||
// PARAM_TYPES: kotlin.String, Comparable<String>, CharSequence, kotlin.Any
|
||||
// PARAM_DESCRIPTOR: internal final class Foo<T> defined in root package
|
||||
// PARAM_DESCRIPTOR: value-parameter val l: kotlin.String defined in Foo.test
|
||||
|
||||
import java.util.*
|
||||
|
||||
// SIBLING:
|
||||
class Foo<T> {
|
||||
val map = HashMap<String, T>()
|
||||
|
||||
fun test(l: String): T {
|
||||
return <selection>map[l]</selection>
|
||||
}
|
||||
}
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
// WITH_RUNTIME
|
||||
// PARAM_TYPES: Foo<T>
|
||||
// PARAM_TYPES: kotlin.String, Comparable<String>, CharSequence, kotlin.Any
|
||||
// PARAM_DESCRIPTOR: internal final class Foo<T> defined in root package
|
||||
// PARAM_DESCRIPTOR: value-parameter val l: kotlin.String defined in Foo.test
|
||||
|
||||
import java.util.*
|
||||
|
||||
// SIBLING:
|
||||
class Foo<T> {
|
||||
val map = HashMap<String, T>()
|
||||
|
||||
fun test(l: String): T {
|
||||
return t(l)
|
||||
}
|
||||
}
|
||||
|
||||
private fun <T> Foo<T>.t(l: String) = map[l]
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
// WITH_RUNTIME
|
||||
// PARAM_TYPES: kotlin.String, Comparable<String>, CharSequence, kotlin.Any
|
||||
// PARAM_DESCRIPTOR: value-parameter val l: kotlin.String defined in Foo.test
|
||||
|
||||
import java.util.*
|
||||
|
||||
class Foo<T> {
|
||||
val map = HashMap<String, T>()
|
||||
|
||||
fun test(l: String): T {
|
||||
return <selection>map[l]</selection>
|
||||
}
|
||||
}
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
// WITH_RUNTIME
|
||||
// PARAM_TYPES: kotlin.String, Comparable<String>, CharSequence, kotlin.Any
|
||||
// PARAM_DESCRIPTOR: value-parameter val l: kotlin.String defined in Foo.test
|
||||
|
||||
import java.util.*
|
||||
|
||||
class Foo<T> {
|
||||
val map = HashMap<String, T>()
|
||||
|
||||
fun test(l: String): T {
|
||||
return t(l)
|
||||
}
|
||||
|
||||
private fun t(l: String) = map[l]
|
||||
}
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
// EXTRACTION_TARGET: property with getter
|
||||
// WITH_RUNTIME
|
||||
|
||||
import java.util.*
|
||||
|
||||
// SIBLING:
|
||||
class Foo<T> {
|
||||
val map = HashMap<String, T>()
|
||||
|
||||
fun test(): T {
|
||||
return <selection>map[""]</selection>
|
||||
}
|
||||
}
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
// EXTRACTION_TARGET: property with getter
|
||||
// WITH_RUNTIME
|
||||
|
||||
import java.util.*
|
||||
|
||||
private val <T> Foo<T>.t: T?
|
||||
get() = map[""]
|
||||
|
||||
// SIBLING:
|
||||
class Foo<T> {
|
||||
val map = HashMap<String, T>()
|
||||
|
||||
fun test(): T {
|
||||
return t
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
// EXTRACTION_TARGET: property with initializer
|
||||
// WITH_RUNTIME
|
||||
|
||||
import java.util.*
|
||||
|
||||
class Foo<T> {
|
||||
val map = HashMap<String, T>()
|
||||
|
||||
fun test(): T {
|
||||
return <selection>map[""]</selection>
|
||||
}
|
||||
}
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
// EXTRACTION_TARGET: property with initializer
|
||||
// WITH_RUNTIME
|
||||
|
||||
import java.util.*
|
||||
|
||||
class Foo<T> {
|
||||
val map = HashMap<String, T>()
|
||||
|
||||
private val t = map[""]
|
||||
|
||||
fun test(): T {
|
||||
return t
|
||||
}
|
||||
}
|
||||
+6
-6
@@ -207,6 +207,7 @@ public abstract class AbstractJetExtractionTest() : JetLightCodeInsightFixtureTe
|
||||
val extractionTarget = propertyTargets.single {
|
||||
it.name == InTextDirectivesUtils.findStringWithPrefixes(file.getText(), "// EXTRACTION_TARGET: ")
|
||||
}
|
||||
val explicitPreviousSibling = file.findElementByComment("// SIBLING:")
|
||||
val helper = object : ExtractionEngineHelper(INTRODUCE_PROPERTY) {
|
||||
override fun configureAndRun(
|
||||
project: Project,
|
||||
@@ -223,12 +224,11 @@ public abstract class AbstractJetExtractionTest() : JetLightCodeInsightFixtureTe
|
||||
)
|
||||
}
|
||||
}
|
||||
KotlinIntroducePropertyHandler(helper).invoke(
|
||||
fixture.getProject(),
|
||||
fixture.getEditor(),
|
||||
file,
|
||||
DataManager.getInstance().getDataContext(fixture.getEditor().getComponent())
|
||||
)
|
||||
val handler = KotlinIntroducePropertyHandler(helper)
|
||||
val editor = fixture.getEditor()
|
||||
handler.selectElements(editor, file) { elements, previousSibling ->
|
||||
handler.doInvoke(getProject(), editor, file as JetFile, elements, explicitPreviousSibling ?: previousSibling)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+24
@@ -1989,6 +1989,18 @@ public class JetExtractionTestGenerated extends AbstractJetExtractionTest {
|
||||
doExtractFunctionTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("typeParameterNotResolvableInTargetScope.kt")
|
||||
public void testTypeParameterNotResolvableInTargetScope() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/extractFunction/typeParameters/typeParameterNotResolvableInTargetScope.kt");
|
||||
doExtractFunctionTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("typeParameterResolvableInTargetScope.kt")
|
||||
public void testTypeParameterResolvableInTargetScope() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/extractFunction/typeParameters/typeParameterResolvableInTargetScope.kt");
|
||||
doExtractFunctionTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("typeParametersAndConstraintsCombined1.kt")
|
||||
public void testTypeParametersAndConstraintsCombined1() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/extractFunction/typeParameters/typeParametersAndConstraintsCombined1.kt");
|
||||
@@ -2196,6 +2208,18 @@ public class JetExtractionTestGenerated extends AbstractJetExtractionTest {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/introduceProperty/replaceDuplicates.kt");
|
||||
doIntroducePropertyTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("typeParameterNotResolvableInTargetScope.kt")
|
||||
public void testTypeParameterNotResolvableInTargetScope() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/introduceProperty/typeParameterNotResolvableInTargetScope.kt");
|
||||
doIntroducePropertyTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("typeParameterResolvableInTargetScope.kt")
|
||||
public void testTypeParameterResolvableInTargetScope() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/introduceProperty/typeParameterResolvableInTargetScope.kt");
|
||||
doIntroducePropertyTest(fileName);
|
||||
}
|
||||
}
|
||||
|
||||
@TestMetadata("idea/testData/refactoring/introduceParameter")
|
||||
|
||||
Reference in New Issue
Block a user