Fix false positive for type error in intentions AddReturnTo...

Relates to #KT-25272
This commit is contained in:
Dmitry Gridin
2019-03-14 10:43:23 +07:00
parent d7ce24410d
commit 179dfce3a8
7 changed files with 74 additions and 4 deletions
@@ -18,6 +18,7 @@ import org.jetbrains.kotlin.psi.KtNamedFunction
import org.jetbrains.kotlin.psi.KtPsiFactory
import org.jetbrains.kotlin.resolve.calls.callUtil.getType
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
import org.jetbrains.kotlin.types.isError
import org.jetbrains.kotlin.types.typeUtil.isSubtypeOf
class AddReturnToLastExpressionInFunctionFix(element: KtDeclarationWithBody) : KotlinQuickFixAction<KtDeclarationWithBody>(element) {
@@ -31,8 +32,9 @@ class AddReturnToLastExpressionInFunctionFix(element: KtDeclarationWithBody) : K
val context = last.analyze(BodyResolveMode.PARTIAL)
val lastType = last.getType(context) ?: return false
if (lastType.isError) return false
val expectedType = element.resolveToDescriptorIfAny()?.returnType ?: return false
if (!lastType.isSubtypeOf(expectedType)) return false
if (expectedType.isError || !lastType.isSubtypeOf(expectedType)) return false
return true
}
@@ -13,10 +13,9 @@ import org.jetbrains.kotlin.diagnostics.Errors
import org.jetbrains.kotlin.idea.caches.resolve.analyze
import org.jetbrains.kotlin.idea.caches.resolve.resolveToDescriptorIfAny
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.bindingContextUtil.isUsedAsStatement
import org.jetbrains.kotlin.resolve.calls.callUtil.getType
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
import org.jetbrains.kotlin.types.isError
import org.jetbrains.kotlin.types.typeUtil.isSubtypeOf
class AddReturnToUnusedLastExpressionInFunctionFix(element: KtElement) : KotlinQuickFixAction<KtElement>(element) {
@@ -29,9 +28,11 @@ class AddReturnToUnusedLastExpressionInFunctionFix(element: KtElement) : KotlinQ
if (!expr.isLastStatementInFunctionBody()) return false
val exprType = expr.getType(context) ?: return false
if (exprType.isError) return false
val function = expr.parent.parent as? KtNamedFunction ?: return false
val functionReturnType = function.resolveToDescriptorIfAny()?.returnType ?: return false
if (!exprType.isSubtypeOf(functionReturnType)) return false
if (functionReturnType.isError || !exprType.isSubtypeOf(functionReturnType)) return false
return true
}
@@ -0,0 +1,10 @@
// "Add 'return' to last expression" "false"
// WITH_RUNTIME
// ACTION: Introduce local variable
// ACTION: Remove explicitly specified return type of enclosing function 'some'
// ERROR: A 'return' expression required in a function with a block body ('{...}')
// ERROR: Unresolved reference: FunctionReference
fun some(): FunctionReference {
Int::class
}<caret>
@@ -0,0 +1,10 @@
// "Add 'return' to last expression" "false"
// WITH_RUNTIME
// ACTION: Introduce local variable
// ACTION: Remove explicitly specified return type of enclosing function 'some'
// ERROR: A 'return' expression required in a function with a block body ('{...}')
// ERROR: Unresolved reference: FunctionReference
fun some(): Any {
FunctionReference::class
}<caret>
@@ -0,0 +1,10 @@
// "Add 'return' before the expression" "false"
// WITH_RUNTIME
// ACTION: Introduce import alias
// ACTION: Introduce local variable
// ERROR: A 'return' expression required in a function with a block body ('{...}')
// ERROR: Unresolved reference: FunctionReference
fun some(): FunctionReference {
Int<caret>::class
}
@@ -0,0 +1,17 @@
// "Add 'return' before the expression" "false"
// WITH_RUNTIME
// ACTION: Create local variable 'FunctionReference'
// ACTION: Create object 'FunctionReference'
// ACTION: Create parameter 'FunctionReference'
// ACTION: Create property 'FunctionReference'
// ACTION: Create annotation 'FunctionReference'
// ACTION: Create class 'FunctionReference'
// ACTION: Create enum 'FunctionReference'
// ACTION: Create interface 'FunctionReference'
// ACTION: Introduce local variable
// ACTION: Rename reference
// ERROR: Unresolved reference: FunctionReference
fun some() {
FunctionReference<caret>::class
}
@@ -933,6 +933,16 @@ public class QuickFixTestGenerated extends AbstractQuickFixTest {
public void testSubtype() throws Exception {
runTest("idea/testData/quickfix/addReturnToLastExpressionInFunction/subtype.kt");
}
@TestMetadata("typeError.kt")
public void testTypeError() throws Exception {
runTest("idea/testData/quickfix/addReturnToLastExpressionInFunction/typeError.kt");
}
@TestMetadata("typeError2.kt")
public void testTypeError2() throws Exception {
runTest("idea/testData/quickfix/addReturnToLastExpressionInFunction/typeError2.kt");
}
}
@TestMetadata("idea/testData/quickfix/addReturnToUnusedLastExpressionInFunction")
@@ -966,6 +976,16 @@ public class QuickFixTestGenerated extends AbstractQuickFixTest {
public void testSubtype() throws Exception {
runTest("idea/testData/quickfix/addReturnToUnusedLastExpressionInFunction/subtype.kt");
}
@TestMetadata("typeError.kt")
public void testTypeError() throws Exception {
runTest("idea/testData/quickfix/addReturnToUnusedLastExpressionInFunction/typeError.kt");
}
@TestMetadata("typeError2.kt")
public void testTypeError2() throws Exception {
runTest("idea/testData/quickfix/addReturnToUnusedLastExpressionInFunction/typeError2.kt");
}
}
@TestMetadata("idea/testData/quickfix/addRunBeforeLambda")