Suspend call detector: fix delegated properties checking
This commit is contained in:
Vendored
+8
@@ -0,0 +1,8 @@
|
|||||||
|
fun bar(d: Delegate): String {
|
||||||
|
val x: String by <!ILLEGAL_SUSPEND_FUNCTION_CALL!>d<!>
|
||||||
|
return x
|
||||||
|
}
|
||||||
|
|
||||||
|
class Delegate {
|
||||||
|
suspend operator fun getValue(thisRef: Any?, property: Any?): String = ""
|
||||||
|
}
|
||||||
Vendored
+11
@@ -0,0 +1,11 @@
|
|||||||
|
package
|
||||||
|
|
||||||
|
public fun bar(/*0*/ d: Delegate): kotlin.String
|
||||||
|
|
||||||
|
public final class Delegate {
|
||||||
|
public constructor Delegate()
|
||||||
|
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||||
|
public final operator suspend fun getValue(/*0*/ thisRef: kotlin.Any?, /*1*/ property: kotlin.Any?): kotlin.String
|
||||||
|
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||||
|
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||||
|
}
|
||||||
@@ -1295,6 +1295,12 @@ public class DiagnosticsTestWithStdLibGenerated extends AbstractDiagnosticsTestW
|
|||||||
doTest(fileName);
|
doTest(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("illegalSuspendCallsForDelegated.kt")
|
||||||
|
public void testIllegalSuspendCallsForDelegated() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/testsWithStdLib/coroutines/illegalSuspendCallsForDelegated.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("irrelevantSuspendDeclarations.kt")
|
@TestMetadata("irrelevantSuspendDeclarations.kt")
|
||||||
public void testIrrelevantSuspendDeclarations() throws Exception {
|
public void testIrrelevantSuspendDeclarations() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/testsWithStdLib/coroutines/irrelevantSuspendDeclarations.kt");
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/testsWithStdLib/coroutines/irrelevantSuspendDeclarations.kt");
|
||||||
|
|||||||
+6
@@ -1295,6 +1295,12 @@ public class DiagnosticsTestWithStdLibUsingJavacGenerated extends AbstractDiagno
|
|||||||
doTest(fileName);
|
doTest(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("illegalSuspendCallsForDelegated.kt")
|
||||||
|
public void testIllegalSuspendCallsForDelegated() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/testsWithStdLib/coroutines/illegalSuspendCallsForDelegated.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("irrelevantSuspendDeclarations.kt")
|
@TestMetadata("irrelevantSuspendDeclarations.kt")
|
||||||
public void testIrrelevantSuspendDeclarations() throws Exception {
|
public void testIrrelevantSuspendDeclarations() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/testsWithStdLib/coroutines/irrelevantSuspendDeclarations.kt");
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/testsWithStdLib/coroutines/irrelevantSuspendDeclarations.kt");
|
||||||
|
|||||||
+20
-4
@@ -24,11 +24,14 @@ import com.intellij.openapi.editor.markup.GutterIconRenderer
|
|||||||
import com.intellij.openapi.progress.ProgressManager
|
import com.intellij.openapi.progress.ProgressManager
|
||||||
import com.intellij.psi.PsiElement
|
import com.intellij.psi.PsiElement
|
||||||
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
||||||
|
import org.jetbrains.kotlin.descriptors.VariableDescriptorWithAccessors
|
||||||
|
import org.jetbrains.kotlin.descriptors.accessors
|
||||||
import org.jetbrains.kotlin.idea.KotlinIcons
|
import org.jetbrains.kotlin.idea.KotlinIcons
|
||||||
import org.jetbrains.kotlin.idea.caches.resolve.analyze
|
import org.jetbrains.kotlin.idea.caches.resolve.analyze
|
||||||
import org.jetbrains.kotlin.idea.refactoring.getLineNumber
|
import org.jetbrains.kotlin.idea.refactoring.getLineNumber
|
||||||
import org.jetbrains.kotlin.psi.*
|
import org.jetbrains.kotlin.psi.*
|
||||||
import org.jetbrains.kotlin.resolve.BindingContext
|
import org.jetbrains.kotlin.resolve.BindingContext
|
||||||
|
import org.jetbrains.kotlin.resolve.BindingContext.*
|
||||||
import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall
|
import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall
|
||||||
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
|
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
|
||||||
|
|
||||||
@@ -76,7 +79,7 @@ class KotlinSuspendCallLineMarkerProvider : LineMarkerProvider {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun KtExpression.isValidCandidateExpression(): Boolean {
|
private fun KtExpression.isValidCandidateExpression(): Boolean {
|
||||||
if (this is KtOperationReferenceExpression || this is KtForExpression) return true
|
if (this is KtOperationReferenceExpression || this is KtForExpression || this is KtProperty) return true
|
||||||
val parent = parent
|
val parent = parent
|
||||||
if (parent is KtCallExpression && parent.calleeExpression == this) return true
|
if (parent is KtCallExpression && parent.calleeExpression == this) return true
|
||||||
return false
|
return false
|
||||||
@@ -87,13 +90,26 @@ fun KtExpression.hasSuspendCalls(bindingContext: BindingContext = analyze(BodyRe
|
|||||||
|
|
||||||
return when (this) {
|
return when (this) {
|
||||||
is KtForExpression -> {
|
is KtForExpression -> {
|
||||||
val iteratorResolvedCall = bindingContext[BindingContext.LOOP_RANGE_ITERATOR_RESOLVED_CALL, loopRange]
|
val iteratorResolvedCall = bindingContext[LOOP_RANGE_ITERATOR_RESOLVED_CALL, loopRange]
|
||||||
val loopRangeHasNextResolvedCall = bindingContext[BindingContext.LOOP_RANGE_HAS_NEXT_RESOLVED_CALL, loopRange]
|
val loopRangeHasNextResolvedCall = bindingContext[LOOP_RANGE_HAS_NEXT_RESOLVED_CALL, loopRange]
|
||||||
val loopRangeNextResolvedCall = bindingContext[BindingContext.LOOP_RANGE_NEXT_RESOLVED_CALL, loopRange]
|
val loopRangeNextResolvedCall = bindingContext[LOOP_RANGE_NEXT_RESOLVED_CALL, loopRange]
|
||||||
listOf(iteratorResolvedCall, loopRangeHasNextResolvedCall, loopRangeNextResolvedCall).any {
|
listOf(iteratorResolvedCall, loopRangeHasNextResolvedCall, loopRangeNextResolvedCall).any {
|
||||||
it?.resultingDescriptor?.isSuspend == true
|
it?.resultingDescriptor?.isSuspend == true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
is KtProperty -> {
|
||||||
|
if (hasDelegateExpression()) {
|
||||||
|
val variableDescriptor = bindingContext[DECLARATION_TO_DESCRIPTOR, this] as? VariableDescriptorWithAccessors
|
||||||
|
val accessors = variableDescriptor?.accessors ?: emptyList()
|
||||||
|
accessors.any { accessor ->
|
||||||
|
val delegatedFunctionDescriptor = bindingContext[DELEGATED_PROPERTY_RESOLVED_CALL, accessor]?.resultingDescriptor
|
||||||
|
delegatedFunctionDescriptor?.isSuspend == true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
else -> {
|
else -> {
|
||||||
val resolvedCall = getResolvedCall(bindingContext)
|
val resolvedCall = getResolvedCall(bindingContext)
|
||||||
(resolvedCall?.resultingDescriptor as? FunctionDescriptor)?.isSuspend == true
|
(resolvedCall?.resultingDescriptor as? FunctionDescriptor)?.isSuspend == true
|
||||||
|
|||||||
@@ -0,0 +1 @@
|
|||||||
|
org.jetbrains.kotlin.idea.inspections.RedundantSuspendModifierInspection
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
// PROBLEM: none
|
||||||
|
// WITH_RUNTIME
|
||||||
|
|
||||||
|
import kotlin.reflect.KProperty
|
||||||
|
|
||||||
|
<caret>suspend fun bar(): String {
|
||||||
|
val x: String by Delegate()
|
||||||
|
return x
|
||||||
|
}
|
||||||
|
|
||||||
|
class Delegate {
|
||||||
|
suspend operator fun getValue(thisRef: Any?, property: KProperty<*>): String = ""
|
||||||
|
}
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
// PROBLEM: none
|
||||||
|
// WITH_RUNTIME
|
||||||
|
|
||||||
|
import kotlin.reflect.KProperty
|
||||||
|
|
||||||
|
<caret>suspend fun bar(): String {
|
||||||
|
var x: String by Delegate()
|
||||||
|
x = "Hello"
|
||||||
|
return x
|
||||||
|
}
|
||||||
|
|
||||||
|
class Delegate {
|
||||||
|
operator fun getValue(thisRef: Any?, property: KProperty<*>): String = ""
|
||||||
|
|
||||||
|
suspend operator fun setValue(thisRef: Any?, property: KProperty<*>, value: String) {}
|
||||||
|
}
|
||||||
@@ -1977,6 +1977,27 @@ public class LocalInspectionTestGenerated extends AbstractLocalInspectionTest {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("idea/testData/inspectionsLocal/redundantSuspend")
|
||||||
|
@TestDataPath("$PROJECT_ROOT")
|
||||||
|
@RunWith(JUnit3RunnerWithInners.class)
|
||||||
|
public static class RedundantSuspend extends AbstractLocalInspectionTest {
|
||||||
|
public void testAllFilesPresentInRedundantSuspend() throws Exception {
|
||||||
|
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/testData/inspectionsLocal/redundantSuspend"), Pattern.compile("^([\\w\\-_]+)\\.kt$"), TargetBackend.ANY, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("getterDelegate.kt")
|
||||||
|
public void testGetterDelegate() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/inspectionsLocal/redundantSuspend/getterDelegate.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("setterDelegate.kt")
|
||||||
|
public void testSetterDelegate() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/inspectionsLocal/redundantSuspend/setterDelegate.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("idea/testData/inspectionsLocal/redundantUnitExpression")
|
@TestMetadata("idea/testData/inspectionsLocal/redundantUnitExpression")
|
||||||
@TestDataPath("$PROJECT_ROOT")
|
@TestDataPath("$PROJECT_ROOT")
|
||||||
@RunWith(JUnit3RunnerWithInners.class)
|
@RunWith(JUnit3RunnerWithInners.class)
|
||||||
|
|||||||
Reference in New Issue
Block a user