Fix false positive for type error in intentions AddReturnTo...
Relates to #KT-25272
This commit is contained in:
+3
-1
@@ -18,6 +18,7 @@ import org.jetbrains.kotlin.psi.KtNamedFunction
|
|||||||
import org.jetbrains.kotlin.psi.KtPsiFactory
|
import org.jetbrains.kotlin.psi.KtPsiFactory
|
||||||
import org.jetbrains.kotlin.resolve.calls.callUtil.getType
|
import org.jetbrains.kotlin.resolve.calls.callUtil.getType
|
||||||
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
|
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
|
||||||
|
import org.jetbrains.kotlin.types.isError
|
||||||
import org.jetbrains.kotlin.types.typeUtil.isSubtypeOf
|
import org.jetbrains.kotlin.types.typeUtil.isSubtypeOf
|
||||||
|
|
||||||
class AddReturnToLastExpressionInFunctionFix(element: KtDeclarationWithBody) : KotlinQuickFixAction<KtDeclarationWithBody>(element) {
|
class AddReturnToLastExpressionInFunctionFix(element: KtDeclarationWithBody) : KotlinQuickFixAction<KtDeclarationWithBody>(element) {
|
||||||
@@ -31,8 +32,9 @@ class AddReturnToLastExpressionInFunctionFix(element: KtDeclarationWithBody) : K
|
|||||||
|
|
||||||
val context = last.analyze(BodyResolveMode.PARTIAL)
|
val context = last.analyze(BodyResolveMode.PARTIAL)
|
||||||
val lastType = last.getType(context) ?: return false
|
val lastType = last.getType(context) ?: return false
|
||||||
|
if (lastType.isError) return false
|
||||||
val expectedType = element.resolveToDescriptorIfAny()?.returnType ?: 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
|
return true
|
||||||
}
|
}
|
||||||
|
|||||||
+4
-3
@@ -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.analyze
|
||||||
import org.jetbrains.kotlin.idea.caches.resolve.resolveToDescriptorIfAny
|
import org.jetbrains.kotlin.idea.caches.resolve.resolveToDescriptorIfAny
|
||||||
import org.jetbrains.kotlin.psi.*
|
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.calls.callUtil.getType
|
||||||
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
|
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
|
||||||
|
import org.jetbrains.kotlin.types.isError
|
||||||
import org.jetbrains.kotlin.types.typeUtil.isSubtypeOf
|
import org.jetbrains.kotlin.types.typeUtil.isSubtypeOf
|
||||||
|
|
||||||
class AddReturnToUnusedLastExpressionInFunctionFix(element: KtElement) : KotlinQuickFixAction<KtElement>(element) {
|
class AddReturnToUnusedLastExpressionInFunctionFix(element: KtElement) : KotlinQuickFixAction<KtElement>(element) {
|
||||||
@@ -29,9 +28,11 @@ class AddReturnToUnusedLastExpressionInFunctionFix(element: KtElement) : KotlinQ
|
|||||||
if (!expr.isLastStatementInFunctionBody()) return false
|
if (!expr.isLastStatementInFunctionBody()) return false
|
||||||
|
|
||||||
val exprType = expr.getType(context) ?: return false
|
val exprType = expr.getType(context) ?: return false
|
||||||
|
if (exprType.isError) return false
|
||||||
|
|
||||||
val function = expr.parent.parent as? KtNamedFunction ?: return false
|
val function = expr.parent.parent as? KtNamedFunction ?: return false
|
||||||
val functionReturnType = function.resolveToDescriptorIfAny()?.returnType ?: 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
|
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>
|
||||||
+10
@@ -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
|
||||||
|
}
|
||||||
+17
@@ -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 {
|
public void testSubtype() throws Exception {
|
||||||
runTest("idea/testData/quickfix/addReturnToLastExpressionInFunction/subtype.kt");
|
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")
|
@TestMetadata("idea/testData/quickfix/addReturnToUnusedLastExpressionInFunction")
|
||||||
@@ -966,6 +976,16 @@ public class QuickFixTestGenerated extends AbstractQuickFixTest {
|
|||||||
public void testSubtype() throws Exception {
|
public void testSubtype() throws Exception {
|
||||||
runTest("idea/testData/quickfix/addReturnToUnusedLastExpressionInFunction/subtype.kt");
|
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")
|
@TestMetadata("idea/testData/quickfix/addRunBeforeLambda")
|
||||||
|
|||||||
Reference in New Issue
Block a user