Supported case when explicit function type is used
This commit is contained in:
+7
-5
@@ -39,6 +39,8 @@ import org.jetbrains.kotlin.resolve.descriptorUtil.isExtension
|
|||||||
import org.jetbrains.kotlin.resolve.descriptorUtil.module
|
import org.jetbrains.kotlin.resolve.descriptorUtil.module
|
||||||
import org.jetbrains.kotlin.resolve.scopes.LexicalScope
|
import org.jetbrains.kotlin.resolve.scopes.LexicalScope
|
||||||
import org.jetbrains.kotlin.resolve.scopes.receivers.ImplicitReceiver
|
import org.jetbrains.kotlin.resolve.scopes.receivers.ImplicitReceiver
|
||||||
|
import org.jetbrains.kotlin.types.KotlinType
|
||||||
|
import org.jetbrains.kotlin.types.TypeUtils
|
||||||
import org.jetbrains.kotlin.types.expressions.ExpressionTypingServices
|
import org.jetbrains.kotlin.types.expressions.ExpressionTypingServices
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
@@ -49,13 +51,14 @@ class ReplacementBuilder(
|
|||||||
fun buildReplacementExpression(
|
fun buildReplacementExpression(
|
||||||
expression: KtExpression,
|
expression: KtExpression,
|
||||||
resolutionScope: LexicalScope,
|
resolutionScope: LexicalScope,
|
||||||
|
expectedType: KotlinType = TypeUtils.NO_EXPECTED_TYPE,
|
||||||
importFqNames: Collection<FqName> = emptyList(),
|
importFqNames: Collection<FqName> = emptyList(),
|
||||||
copyExpression: Boolean = true
|
copyExpression: Boolean = true
|
||||||
): ReplacementExpression {
|
): ReplacementExpression {
|
||||||
@Suppress("NAME_SHADOWING")
|
@Suppress("NAME_SHADOWING")
|
||||||
var expression = if (copyExpression) expression.copied() else expression
|
var expression = if (copyExpression) expression.copied() else expression
|
||||||
|
|
||||||
var bindingContext = analyzeInContext(expression, resolutionScope)
|
var bindingContext = analyzeInContext(expression, resolutionScope, expectedType)
|
||||||
|
|
||||||
val typeArgsToAdd = ArrayList<Pair<KtCallExpression, KtTypeArgumentList>>()
|
val typeArgsToAdd = ArrayList<Pair<KtCallExpression, KtTypeArgumentList>>()
|
||||||
expression.forEachDescendantOfType<KtCallExpression> {
|
expression.forEachDescendantOfType<KtCallExpression> {
|
||||||
@@ -70,7 +73,7 @@ class ReplacementBuilder(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// reanalyze expression - new usages of type parameters may be added
|
// reanalyze expression - new usages of type parameters may be added
|
||||||
bindingContext = analyzeInContext(expression, resolutionScope)
|
bindingContext = analyzeInContext(expression, resolutionScope, expectedType)
|
||||||
}
|
}
|
||||||
|
|
||||||
val receiversToAdd = ArrayList<Pair<KtExpression, KtExpression>>()
|
val receiversToAdd = ArrayList<Pair<KtExpression, KtExpression>>()
|
||||||
@@ -122,8 +125,7 @@ class ReplacementBuilder(
|
|||||||
return ReplacementExpression(expression, resultImportFqNames)
|
return ReplacementExpression(expression, resultImportFqNames)
|
||||||
}
|
}
|
||||||
|
|
||||||
//TODO: there can be expected type and maybe something else
|
private fun analyzeInContext(expression: KtExpression, scope: LexicalScope, expectedType: KotlinType): BindingContext {
|
||||||
private fun analyzeInContext(expression: KtExpression, scope: LexicalScope): BindingContext {
|
|
||||||
val module = scope.ownerDescriptor.module
|
val module = scope.ownerDescriptor.module
|
||||||
val frontendService = if (module.builtIns.builtInsModule == module) {
|
val frontendService = if (module.builtIns.builtInsModule == module) {
|
||||||
// TODO: doubtful place, do we require this module or not? Built-ins module doesn't have some necessary components...
|
// TODO: doubtful place, do we require this module or not? Built-ins module doesn't have some necessary components...
|
||||||
@@ -132,6 +134,6 @@ class ReplacementBuilder(
|
|||||||
else {
|
else {
|
||||||
resolutionFacade.getFrontendService(module, ExpressionTypingServices::class.java)
|
resolutionFacade.getFrontendService(module, ExpressionTypingServices::class.java)
|
||||||
}
|
}
|
||||||
return expression.analyzeInContext(scope, expressionTypingServices = frontendService)
|
return expression.analyzeInContext(scope, expectedType = expectedType, expressionTypingServices = frontendService)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+1
-1
@@ -76,7 +76,7 @@ object ReplaceWithAnnotationAnalyzer {
|
|||||||
listOf(explicitImportsScope) + defaultImportsScopes) ?: return null
|
listOf(explicitImportsScope) + defaultImportsScopes) ?: return null
|
||||||
|
|
||||||
return ReplacementBuilder(symbolDescriptor, resolutionFacade)
|
return ReplacementBuilder(symbolDescriptor, resolutionFacade)
|
||||||
.buildReplacementExpression(expression, scope, importFqNames(annotation), copyExpression = false)
|
.buildReplacementExpression(expression, scope, importFqNames = importFqNames(annotation), copyExpression = false)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun analyzeClassReplacement(
|
fun analyzeClassReplacement(
|
||||||
|
|||||||
+6
-1
@@ -32,6 +32,7 @@ import org.jetbrains.kotlin.idea.replacement.ReplacementBuilder
|
|||||||
import org.jetbrains.kotlin.idea.replacement.replaceUsagesInWholeProject
|
import org.jetbrains.kotlin.idea.replacement.replaceUsagesInWholeProject
|
||||||
import org.jetbrains.kotlin.idea.util.getResolutionScope
|
import org.jetbrains.kotlin.idea.util.getResolutionScope
|
||||||
import org.jetbrains.kotlin.psi.KtNamedFunction
|
import org.jetbrains.kotlin.psi.KtNamedFunction
|
||||||
|
import org.jetbrains.kotlin.types.TypeUtils
|
||||||
|
|
||||||
class KotlinInlineFunctionHandler: InlineActionHandler() {
|
class KotlinInlineFunctionHandler: InlineActionHandler() {
|
||||||
override fun isEnabledForLanguage(language: Language) = language == KotlinLanguage.INSTANCE
|
override fun isEnabledForLanguage(language: Language) = language == KotlinLanguage.INSTANCE
|
||||||
@@ -48,8 +49,12 @@ class KotlinInlineFunctionHandler: InlineActionHandler() {
|
|||||||
val descriptor = element.resolveToDescriptor() as SimpleFunctionDescriptor
|
val descriptor = element.resolveToDescriptor() as SimpleFunctionDescriptor
|
||||||
|
|
||||||
val bodyExpression = element.bodyExpression!!
|
val bodyExpression = element.bodyExpression!!
|
||||||
|
val expectedType = if (element.hasDeclaredReturnType())
|
||||||
|
descriptor.returnType ?: TypeUtils.NO_EXPECTED_TYPE
|
||||||
|
else
|
||||||
|
TypeUtils.NO_EXPECTED_TYPE
|
||||||
val replacement = ReplacementBuilder(descriptor, element.getResolutionFacade())
|
val replacement = ReplacementBuilder(descriptor, element.getResolutionFacade())
|
||||||
.buildReplacementExpression(bodyExpression, bodyExpression.getResolutionScope())
|
.buildReplacementExpression(bodyExpression, bodyExpression.getResolutionScope(), expectedType)
|
||||||
|
|
||||||
val commandName = RefactoringBundle.message("inline.command", element.name)
|
val commandName = RefactoringBundle.message("inline.command", element.name)
|
||||||
CallableUsageReplacementStrategy(replacement)
|
CallableUsageReplacementStrategy(replacement)
|
||||||
|
|||||||
+6
@@ -0,0 +1,6 @@
|
|||||||
|
fun <caret>f(): List<String> = emptyList()
|
||||||
|
|
||||||
|
fun main(args: Array<String>) {
|
||||||
|
val list1 = f()
|
||||||
|
val list2: List<String> = f()
|
||||||
|
}
|
||||||
+4
@@ -0,0 +1,4 @@
|
|||||||
|
fun main(args: Array<String>) {
|
||||||
|
val list1 = emptyList<String>()
|
||||||
|
val list2: List<String> = emptyList()
|
||||||
|
}
|
||||||
@@ -69,6 +69,12 @@ public class InlineTestGenerated extends AbstractInlineTest {
|
|||||||
doTest(fileName);
|
doTest(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("ExplicitReturnType.kt")
|
||||||
|
public void testExplicitReturnType() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/refactoring/inline/function/expressionBody/ExplicitReturnType.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("FromUsage.kt")
|
@TestMetadata("FromUsage.kt")
|
||||||
public void testFromUsage() throws Exception {
|
public void testFromUsage() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/refactoring/inline/function/expressionBody/FromUsage.kt");
|
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/refactoring/inline/function/expressionBody/FromUsage.kt");
|
||||||
|
|||||||
Reference in New Issue
Block a user