Supported case when explicit function type is used

This commit is contained in:
Valentin Kipyatkov
2016-10-21 12:45:59 +03:00
parent 9490d1bb1c
commit 3b97a3feb1
6 changed files with 30 additions and 7 deletions
@@ -39,6 +39,8 @@ import org.jetbrains.kotlin.resolve.descriptorUtil.isExtension
import org.jetbrains.kotlin.resolve.descriptorUtil.module
import org.jetbrains.kotlin.resolve.scopes.LexicalScope
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 java.util.*
@@ -49,13 +51,14 @@ class ReplacementBuilder(
fun buildReplacementExpression(
expression: KtExpression,
resolutionScope: LexicalScope,
expectedType: KotlinType = TypeUtils.NO_EXPECTED_TYPE,
importFqNames: Collection<FqName> = emptyList(),
copyExpression: Boolean = true
): ReplacementExpression {
@Suppress("NAME_SHADOWING")
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>>()
expression.forEachDescendantOfType<KtCallExpression> {
@@ -70,7 +73,7 @@ class ReplacementBuilder(
}
// 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>>()
@@ -122,8 +125,7 @@ class ReplacementBuilder(
return ReplacementExpression(expression, resultImportFqNames)
}
//TODO: there can be expected type and maybe something else
private fun analyzeInContext(expression: KtExpression, scope: LexicalScope): BindingContext {
private fun analyzeInContext(expression: KtExpression, scope: LexicalScope, expectedType: KotlinType): BindingContext {
val module = scope.ownerDescriptor.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...
@@ -132,6 +134,6 @@ class ReplacementBuilder(
else {
resolutionFacade.getFrontendService(module, ExpressionTypingServices::class.java)
}
return expression.analyzeInContext(scope, expressionTypingServices = frontendService)
return expression.analyzeInContext(scope, expectedType = expectedType, expressionTypingServices = frontendService)
}
}
@@ -76,7 +76,7 @@ object ReplaceWithAnnotationAnalyzer {
listOf(explicitImportsScope) + defaultImportsScopes) ?: return null
return ReplacementBuilder(symbolDescriptor, resolutionFacade)
.buildReplacementExpression(expression, scope, importFqNames(annotation), copyExpression = false)
.buildReplacementExpression(expression, scope, importFqNames = importFqNames(annotation), copyExpression = false)
}
fun analyzeClassReplacement(
@@ -32,6 +32,7 @@ import org.jetbrains.kotlin.idea.replacement.ReplacementBuilder
import org.jetbrains.kotlin.idea.replacement.replaceUsagesInWholeProject
import org.jetbrains.kotlin.idea.util.getResolutionScope
import org.jetbrains.kotlin.psi.KtNamedFunction
import org.jetbrains.kotlin.types.TypeUtils
class KotlinInlineFunctionHandler: InlineActionHandler() {
override fun isEnabledForLanguage(language: Language) = language == KotlinLanguage.INSTANCE
@@ -48,8 +49,12 @@ class KotlinInlineFunctionHandler: InlineActionHandler() {
val descriptor = element.resolveToDescriptor() as SimpleFunctionDescriptor
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())
.buildReplacementExpression(bodyExpression, bodyExpression.getResolutionScope())
.buildReplacementExpression(bodyExpression, bodyExpression.getResolutionScope(), expectedType)
val commandName = RefactoringBundle.message("inline.command", element.name)
CallableUsageReplacementStrategy(replacement)
@@ -0,0 +1,6 @@
fun <caret>f(): List<String> = emptyList()
fun main(args: Array<String>) {
val list1 = f()
val list2: List<String> = f()
}
@@ -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);
}
@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")
public void testFromUsage() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/refactoring/inline/function/expressionBody/FromUsage.kt");